# Redis for Laravel on a private network, over TLS

How a serverless Laravel app gets a Scaleway Managed Database for Redis on a Private Network, over TLS, and what to keep in it on serverless containers.

## In short

- The cache key in brewless.yml gives a Laravel environment a Scaleway Managed Database for Redis, reached over a Private Network only and over TLS.
- A cache brings network private along, which puts the web, release and worker containers on the Private Network of the Scaleway project.
- Brewless sets CACHE_STORE, REDIS_CLIENT, REDIS_HOST, REDIS_PORT, REDIS_USERNAME, REDIS_PASSWORD and BREWLESS_REDIS_CA, and brewless/laravel 0.8 or later makes the connection trust only that certificate.
- A Redis cache is billed every hour it exists, because unlike a serverless container or database it does not sleep.
- On serverless containers Redis suits the cache, sessions and locks, while jobs wait at Scaleway Queues or in the database.

A serverless Laravel app keeps its cache in the database by default, and for many apps that is fine. Once the cache gets busy, or you would rather let a serverless database sleep between visits, Redis is the usual next step. On Scaleway that is a Managed Database for Redis, and the safe way to reach it is over a Private Network, with TLS.

This post shows how to add one to a Laravel environment with [Brewless](/), what Brewless sets up, and what belongs in Redis when your containers come and go.

## How does a serverless Laravel app use Redis on Scaleway?

Through `cache` in `brewless.yml`. Brewless gives the environment a Scaleway Managed Database for Redis, puts the containers on the project's Private Network, and sets `CACHE_STORE=redis` and the `REDIS_*` variables. With `brewless/laravel` 0.8 or later, the connection speaks TLS and trusts only the certificate of that cache.

## Add the cache

```yaml brewless.yml
environments:
  production:
    region: fr-par
    database: shop-main
    cache: shop-cache
  staging:
    region: fr-par
    database: shop-staging
    cache:
      name: shop-staging-cache
      size: RED1-XS
```

On the next deploy, Brewless looks for a cache of that name in the region. One that stands is used as it is. Otherwise it makes one with the size you gave and the newest version of Redis Scaleway offers.

| Key | What it does |
| --- | --- |
| `cache: <name>` | Uses or makes a cache of that name, size `RED1-micro` |
| `cache.name` | The name of the cache at Scaleway |
| `cache.size` | The node type of a new cache: `RED1-micro`, `RED1-2XS`, `RED1-XS`, `RED1-S`, `RED1-M`, `RED1-L` or `RED1-XL` |
| `cache: false` | Lets the cache go from the environment; it keeps running at Scaleway |

Run `brewless plan production` first to see what the file asks for next to what stands.

> [!WARNING]
> Scaleway bills a cache by its size, for every hour it exists. A cache does not sleep. `cache: false` takes it out of the environment, but it keeps running, and costing, until you remove it in your Scaleway console.

A cache that stands is not swapped for another name or size from `brewless.yml`; a deploy that asks for that is refused. Scaleway offers Managed Database for Redis in Paris, Amsterdam and Warsaw, not in Milan.

## The Private Network

A cache is reached over the project's Private Network only, so `cache` brings `network: private` along. You can also set it on its own:

```yaml brewless.yml
environments:
  production:
    network: private
```

What that does:

- Each Scaleway project gets one Private Network per region, called `brewless`, made the first time an environment asks for it. Every environment of the project that says `network: private` joins it. Scaleway does not charge for a Private Network.
- The web, release and worker containers go on it. For an environment that runs already, Scaleway deploys them again for that.
- A Managed Database the environment uses gets a private endpoint on the network, and `DB_HOST` and `DB_PORT` move to it unless you set them yourself. Its public endpoint stays; remove it in your Scaleway console once nothing uses it.
- A Serverless SQL Database cannot join a network. It stays as it is, reached over the internet with its key, next to a cache on the network.

An environment does not leave the network from `brewless.yml`: `network: public` for an environment on it is refused. A container or database that is on another Private Network already is not moved; setting up stops and says which. See [A Private Network](https://docs.brewless.eu/applications/applications-and-environments#a-private-network).

## The variables Brewless sets

| Variable | Value |
| --- | --- |
| `CACHE_STORE` | `redis` |
| `REDIS_CLIENT` | `phpredis` |
| `REDIS_HOST`, `REDIS_PORT` | The cache's endpoint on the Private Network |
| `REDIS_USERNAME`, `REDIS_PASSWORD` | The user `brewless` of a cache Brewless made |
| `BREWLESS_REDIS_CA` | The certificate of the cache's cluster |

For a cache Brewless makes, the password of the `brewless` user goes into your own Secret Manager, as `<application>-<environment>-cache-key`, before the cache is made. Brewless never keeps it. A cache that stood there already has users of your own making, so `REDIS_USERNAME` and `REDIS_PASSWORD` are left for you to set with `brewless env:push`.

Laravel's default `config/database.php` reads these names. TLS is the one thing Laravel's default config does not set up from a variable. Require the package version that does:

```bash
composer require brewless/laravel:^0.8
```

With 0.8 or later, your redis connections speak TLS and trust the certificate in `BREWLESS_REDIS_CA`, and no other. A Private Network already keeps the traffic inside your project; TLS means the password and data are not readable on that network either.

> [!NOTE]
> A variable change reaches the containers with the next deploy. Adding `cache` to an environment that runs puts the variables in the same deploy, as a new revision of the environment's variables.

## What to keep in Redis on serverless

Serverless containers start and stop all day, and two of them never share memory or disk. Anything that has to be shared between requests goes to a store outside the container. Redis is a good fit for some of that, and not for all of it.

| What | Where | Why |
| --- | --- | --- |
| Cache | Redis | Brewless sets `CACHE_STORE=redis` for you |
| Locks (`Cache::lock`, `withoutOverlapping`, `onOneServer`) | Redis | Locks use the cache store, so they move with it |
| Sessions | Redis, if you set `SESSION_DRIVER=redis` | Fast, and takes a query off the database per request |
| Rate limiting | Redis | Uses the cache store |
| Jobs | Scaleway Queues or the database | Brewless's queue choices are `sqs`, `database` or none |
| Anything you cannot rebuild | The database or a bucket | A cache is for what you can work out again |

**Cache.** Fragments, expensive queries and the answers of slow services. With the cache in Redis, a page that only reads from the cache does not touch the database.

**Locks.** `Cache::lock()`, the scheduler's `withoutOverlapping()` and `onOneServer()` all go through the cache store. On serverless, where several replicas can run the same code at once, those locks are what keep a task from running twice. In Redis they are shared by every container of the environment.

**Sessions.** Brewless leaves `SESSION_DRIVER` alone. Set it to `redis` when you want sessions there; on a serverless database that saves a query on every request. Keep in mind that a session in a cache lives only as long as the cache does.

**Jobs.** The worker of an environment is called by Scaleway Queues as soon as a job is put on it, or by a trigger every minute when jobs wait in the database. The cache is not one of those choices. See [Queues and schedule](https://docs.brewless.eu/running/queues-and-schedule).

> [!TIP]
> If you moved to Redis so a Serverless SQL Database can sleep, check the rest of the app too. Jobs that wait in the database, or a schedule that runs every minute, keep it awake whatever the cache does. Read [Serverless SQL or Managed PostgreSQL for Laravel](/blog/serverless-sql-or-managed-postgresql).

## Summary

1. Add `cache` with a name, and a size if `RED1-micro` is too small, in Paris, Amsterdam or Warsaw.
2. Accept that the environment joins the project's Private Network, and remove the public endpoint of a managed database yourself once nothing uses it.
3. Require `brewless/laravel` 0.8 or later so the connection uses TLS.
4. Keep the cache, locks and, if you want, sessions in Redis; keep jobs at Scaleway Queues or in the database.
5. Remember that the cache bills every hour, and that `cache: false` does not remove it.

The full description is in [A cache](https://docs.brewless.eu/applications/applications-and-environments#a-cache).

## Frequently asked questions

### How do I add Redis to a Laravel app on Brewless?

Add cache with a name under the environment in brewless.yml and deploy. Brewless uses a cache of that name in the region or makes one, puts the environment on the Private Network, and sets CACHE_STORE=redis and the REDIS_* variables.

### Is the Redis cache reachable from the internet?

No. It is reached over the Private Network of your Scaleway project only, which nothing outside the project can reach, and the connection uses TLS on top of that.

### Which Redis sizes can I choose?

Scaleway's node types from RED1-micro to RED1-XL, set with cache.size. Without a size a new cache gets RED1-micro. A cache that stands is not resized from brewless.yml; that is refused.

### Does Brewless put Laravel sessions in Redis?

Brewless sets CACHE_STORE=redis only. Laravel can keep its sessions and locks in the same cache, but you choose that yourself, for example with SESSION_DRIVER=redis in your variables.

### In which regions is Managed Database for Redis available?

Scaleway offers it in Paris, Amsterdam and Warsaw, not in Milan. An environment in Milan cannot have a cache from brewless.yml.

Source: https://test.brewless.eu/blog/laravel-redis-private-network-tls
