Zero-dependency deployment for Phoenix applications. If your server has Bash and SSH, hawk works.
0611.2.mp4
Deploying Phoenix applications to a Linux server should not require another language runtime.
Capistrano requires Ruby. Deployer requires PHP. Fabric requires Python. A Phoenix app already has enough moving parts, so hawk keeps deployment in the tools every Linux server already has: Bash and SSH.
The goal is a deploy tool you can read, understand, and change when your application needs something specific.
- No runtime dependencies beyond Bash, SSH, and the standard tools already present on most Linux servers.
- Capistrano-style releases with timestamped release directories, a
currentsymlink, and instant rollback. - Phoenix-focused deploy flow for Mix releases, migrations, and systemd services.
- ShellCheck-clean Bash code instead of an unstructured deploy script.
- Modular command files, so new commands can be added without rewriting the router.
- Colored terminal output and timestamped logs, so you can see what happened during a deploy.
- Built-in status, logs, doctor, backup, restore, and rollback commands for common operations.
- Bash 4 or newer.
git.ssh.rsync.- A Linux server reachable over SSH.
- A Git repository that the server can clone.
systemdon the server for service management and log inspection.
shellcheck.
On macOS, the system Bash is usually too old. Install a newer Bash with Homebrew:
brew install bashClone the repository:
git clone https://github.com/Null-logic-0/hawk.git
cd hawkMake the CLI executable:
chmod +x bin/hawkRun it from the repository:
./bin/hawk --helpOr add a symlink somewhere on your PATH:
mkdir -p "$HOME/.local/bin"
ln -sf "$PWD/bin/hawk" "$HOME/.local/bin/hawk"
hawk --help- Install hawk:
git clone https://github.com/Null-logic-0/hawk.git
cd hawk
chmod +x bin/hawk-
Ensure your app has a
Releasemodule. See the Phoenix releases guide. -
Initialize hawk in your Phoenix project:
hawk init- Review the generated config:
cat hawk.conf- Copy the generated systemd service to the server:
scp my_app.service deploy@example.com:/tmp/my_app.service
ssh deploy@example.com "sudo mv /tmp/my_app.service /etc/systemd/system/my_app.service"- Enable the service on the server:
ssh deploy@example.com "sudo systemctl daemon-reload && sudo systemctl enable my_app"- Check the setup:
hawk doctor- Deploy:
hawk deploy- Check the service:
hawk status
hawk logshawk reads deployment settings from hawk.conf in the current directory or a parent directory. Generate one with:
hawk initMinimal example:
APP_NAME=my_app
SERVER_HOST=example.com
SERVER_USER=deploy
SERVER_PORT=22
DEPLOY_PATH=/var/www/my_app
GIT_BRANCH=main
GIT_REPO=git@github.com:example/my_app.git
APP_ENV=production
RELEASES_TO_KEEP=5
RELEASE_MODULE=MyApp
BACKUP_PATH=/var/backups/my_app
DB_USER=my_app
DB_NAME=my_app_prodRequired fields:
APP_NAMESERVER_HOSTSERVER_USERGIT_REPODB_USERDB_NAMERELEASE_MODULE
For every config key, defaults, path layout, release module setup, Git access, and backup behavior, see docs/configuration.md.
Show help:
hawk help
hawk --helpShow the installed version:
hawk versionCreate hawk.conf and a systemd service file:
hawk initRun setup checks before deploying:
hawk doctorDeploy the configured branch:
hawk deployShow the current release, available releases, and systemd status:
hawk statusShow the last 100 service log lines:
hawk logsStream service logs:
hawk logs --follow
hawk logs -fRoll back to the previous release:
hawk rollbackCreate a database and release backup:
hawk backupRestore from an existing backup:
hawk restoreThe server needs:
- Bash.
- SSH access for
SERVER_USER. gitso the server can cloneGIT_REPO.- Erlang, Elixir, and Mix versions compatible with the Phoenix app.
- PostgreSQL client tools:
pg_dumpandpsql. gzipandtarfor backups.systemdfor service management.- Passwordless sudo for
systemctl restart APP_NAME, or another sudo setup that works in non-interactive SSH commands. - A writable deploy directory, usually
DEPLOY_PATH.
Create the deploy directory:
ssh deploy@example.com "sudo mkdir -p /var/www/my_app/releases && sudo chown -R deploy:deploy /var/www/my_app"Install the generated service:
scp my_app.service deploy@example.com:/tmp/my_app.service
ssh deploy@example.com "sudo mv /tmp/my_app.service /etc/systemd/system/my_app.service"
ssh deploy@example.com "sudo systemctl daemon-reload && sudo systemctl enable my_app"Run the local test suite with Bash 4 or newer:
bash tests/run_tests.shOn macOS, use Homebrew Bash if /bin/bash is still version 3:
/opt/homebrew/bin/bash tests/run_tests.shRun ShellCheck:
shellcheck bin/hawk lib/*.sh commands/*.sh tests/*.sh- Fork the repository.
- Create a branch:
git checkout -b my-change- Make the change.
- Run the tests and ShellCheck:
bash tests/run_tests.sh
shellcheck bin/hawk lib/*.sh commands/*.sh tests/*.sh- Commit with a clear message:
git commit -m "feat: describe the change"- Open a pull request.
Keep changes small, readable, and ShellCheck-clean. New commands should live in commands/ and be routed from bin/hawk.
MIT. See LICENSE.
