# Versioned releases with a symlink layout

By default, your website is served from a single `public_html` directory in your home
directory. That works well for a manual upload, but continuous integration and continuous
deployment (CI/CD) pipelines usually expect a different layout: each deploy lands in its own
`releases/` folder, and a `current` symlink points at the release that is live. Switching the
symlink makes a new version go live in one step, and switching it back is an instant rollback.

This page shows you how to replace `public_html` with that layout. Your web root stays at
`~/public_html`, so nothing changes for the web server: you only change what it points to.

> [!NOTE]
> Deploy tools such as Deployer, Envoyer, and most custom CI/CD scripts create this structure
> for you. This page prepares the home directory so those tools can take over the `public_html`
> path.

## The target layout

You are aiming for a home directory where `public_html` is a symlink into a versioned release,
rather than a real directory:

```bash
current -> releases/<current-release>
public_html -> current
releases/
shared/
```

- `releases/` holds one directory per deploy (often named by timestamp or commit).
- `current` is a symlink to the release that should be live.
- `shared/` holds files that must survive between releases (uploads, `.env`, caches).
- `public_html` is a symlink to `current`, so the web server always serves the live release.

## Step-by-step

Connect to the host over SSH first (see the host [SSH](../platform/hosts/ssh.md) tab). Run the
commands from your home directory.

1. Remove the existing `public_html` directory. This command only succeeds if the directory is
   empty, which protects you from deleting a live site by accident:

   ```bash
   rmdir ~/public_html
   ```

   If `rmdir` reports that the directory is not empty, do not force it. Move your current site
   into a first release directory instead, then continue.

2. Create the `releases/` and `shared/` directories, or run a deploy so your pipeline creates
   them. This page assumes your code is already laid out with a `current` symlink pointing at a
   release, for example `current -> releases/2026-07-24-1`.

3. Point `public_html` at the `current` symlink:

   ```bash
   ln -s current public_html
   ```

4. Verify that the symlinks resolve as expected:

   ```bash
   ls -l
   # current      -> releases/<current-release>
   # public_html  -> current
   # releases/
   # shared/
   ```

From now on, your pipeline deploys a new release, repoints `current`, and the change is live
immediately. To roll back, repoint `current` to the previous release.

## A different root directory

Some frameworks keep `current` and `releases/` inside a subdirectory, for example
`application/`. In that case, only step 3 changes: point `public_html` at the `current` symlink
under that subdirectory.

```bash
ln -s application/current public_html
```

> [!WARNING]
> `public_html` is your live web root. If the symlink points at a path that does not exist,
> your site returns an error until you fix it. Always confirm with `ls -l` that
> `public_html -> current` and that `current` resolves to a real release.

## Related

- [Host SSH tab](../platform/hosts/ssh.md)
- [What is SSH?](../technologies/ssh/what-is.md)
- [Deployment history](../platform/hosts/revisions.md)
- [Applications](../platform/hosts/applications/index.md)
- [Finding and reading logs](../troubleshooting/finding-logs.md)
