# Relay: manual cPanel installation with JSON storage

Relay uses JSON files for its application data. No MySQL database, AI assistant, or installation wizard is required. All included features are free.

## Requirements

- A cPanel domain or subdomain with a valid SSL certificate and Apache rewrite support.
- PHP 8.1 or newer with JSON, sessions, file locking (`flock`) and a password-hashing implementation. The PHP process must be able to write and rename files in the private `storage` directory.
- A single server and a local filesystem that supports reliable advisory locks and atomic file replacement. Network filesystems and multiple web servers are not supported by this storage design.
- PHP must see `HTTPS` as enabled on secure requests. A reverse proxy that does not set this server-side value needs hosting-specific configuration. Relay does not trust a client-supplied forwarded-protocol header.

## 1. Upload the application

Extract `relay-cpanel.zip` into a private directory such as `/home/CPANEL_USER/relay`. Set the domain's document root to `/home/CPANEL_USER/relay/public`. Only `public` may be web-accessible. Do not extract the entire application into `public_html`; never expose `.env`, `storage`, `src`, or `tools` through the website. Confirm that `public/.htaccess` and `storage/.htaccess` are present, including their leading dots. Enable the host's HTTPS certificate.

Ensure the PHP process can read and write the `storage` directory; directories commonly use permission `700` when owned by the PHP user, but your host may require a different private setting. Do not make storage publicly accessible. The application creates `storage/relay.json`, a separate lock file, and temporary files as needed. Do not delete the lock file while the application is running.

## 2. Configure the site

Copy `.env.example` to `.env` in the private application directory. Edit:

```text
APP_ENV=production
APP_URL=https://links.example.com
APP_KEY=your-unique-random-secret-at-least-32-bytes-long
ALLOW_REGISTRATION=false
ANALYTICS_RETENTION_DAYS=90
```

Replace the examples. `APP_URL` must be the HTTPS origin only, without a trailing path. To generate a key in cPanel Terminal, run `php -r 'echo bin2hex(random_bytes(32)), PHP_EOL;'` and paste the result into `APP_KEY`. Keep `.env` private, with permissions such as `600` subject to your hosting account's PHP access requirements. Configuration uses plain `KEY=value` lines without surrounding quotes.

By default, Relay uses `storage/relay.json`. An optional absolute `JSON_FILE` path may be configured in `.env`; its parent must already exist, be writable, and be outside the `public` directory. Keep the data file, its `.lock` file, and any backups private. The data includes password hashes and link, analytics and account records.

## 3. Create the administrator

In cPanel Terminal, enter the application directory and run the following, substituting your email. The password is read without displaying it and is passed through standard input:

```sh
cd /home/CPANEL_USER/relay
read -rs -p 'Administrator password: ' RELAY_ADMIN_PASSWORD; printf '\n'
printf '%s\n' "$RELAY_ADMIN_PASSWORD" | php tools/create-admin.php admin@example.com
unset RELAY_ADMIN_PASSWORD
```

Use a unique password of 12–72 bytes. Sign in, then open **Administration** from the dashboard. If Terminal is unavailable, ask the hosting provider to run the command. Registration is initially closed; set `ALLOW_REGISTRATION=true` after creating your administrator if you want visitors to register. Review abuse reports actively before opening a public link service.

## 4. Schedule cleanup and back up

In cPanel Cron Jobs, run this once daily, replacing the path and PHP binary with those used by your host:

```text
15 2 * * * /usr/local/bin/php /home/CPANEL_USER/relay/tools/prune.php
```

The command removes individual click records older than `ANALYTICS_RETENTION_DAYS` and expired rate-limit entries. Lifetime click totals remain on links, so they can exceed the retained detail count. Back up `.env` and `storage/relay.json` privately and test a restore. To obtain a consistent backup, stop incoming requests and maintenance jobs first; preserve the application key with the data. This project does not provide a backup scheduler.

## 5. Verify on the actual host

1. Check that HTTPS loads the homepage, HTTP redirects to the configured HTTPS origin, and `.env`, `storage/relay.json` and private source files cannot be downloaded.
2. Sign in as administrator. Create a link to a website you control, open it, and check its visit in the dashboard and analytics. Test aliases, pause, expiry, passwords and a QR scan from another device.
3. Test an API key if needed. Apache must forward the Authorization header.
4. Test masking only with destinations that permit embedding. Smart reveal additionally requires the supplied SDK on the destination you control. Without the integration, navigation may remain inside the frame; some destinations block framing entirely.
5. Confirm your cron job and a backup restore. Verify file locking with your hosting provider if unsure.

## Limits and upgrading

JSON storage reads and rewrites the data file under a shared lock, including when recording clicks. It is suitable only for modest traffic on one server and can become slow or exhaust disk space as traffic grows. It is not a high-volume or distributed database. Set retention, monitor disk space, keep tested backups, and use a database-backed edition if traffic grows. Local concurrency tests cannot guarantee the locking behavior of every host's filesystem.

This is a new JSON storage format. It does not automatically import an existing MySQL or SQLite installation. Back up an older installation and its database before changing versions; existing accounts, links and analytics will not appear in a fresh JSON file. No automated migration tool is included.

This package includes only the implemented features. Password reset, email verification, automatic malware screening, custom-domain verification, GA4 consent controls and other items from the original brief remain unfinished. Actual cPanel, SSL, browser/device and independent security verification remain necessary before a public launch.
