# Swap memory

**URL:** <https://community.fly.io/t/swap-memory/2749>\
**Category:** General\
**Created:** [October 7, 2021, 10:03pm UTC](https://community.fly.io/t/swap-memory/2749 "2021-10-07T22:03:55Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![balexander](https://avatars.discourse-cdn.com/v4/letter/b/9de053/32.png) [@balexander](https://community.fly.io/u/balexander)\
**Post date:** [October 7, 2021, 10:03pm UTC](https://community.fly.io/t/swap-memory/2749/1 "2021-10-07T22:03:55Z")

</div>

Hi. Is there a way to configure swap memory for a Fly app? Or is this something that should configured in the Docker image (I’m using `alpine:3.13`)? I just SSHed into my instance and it looks like there is no swap configured.

```auto
# free -m
              total used free shared buff/cache available
Mem: 228 83 69 35 74 117
Swap: 0 0 0

```

Thanks 🙂

---

<div class="post-metadata">

**Author:** ![OldhamMade](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/oldhammade/32/40954_2.png) [@OldhamMade](https://community.fly.io/u/OldhamMade)\
**Post date:** [November 1, 2021, 6:19am UTC](https://community.fly.io/t/swap-memory/2749/2 "2021-11-01T06:19:08Z")

</div>

Hi, I’ve just confirmed a deploy based on alpine using this as the final line in my `Dockerfile`:

```auto
CMD if [[! -z "$SWAP"]]; then fallocate -l $(($(stat -f -c "(%a*%s/10)*7" .))) _swapfile && mkswap _swapfile && swapon _swapfile && ls -hla; fi; free -m; /app/run

```

You then need to set `SWAP="true"` in your `fly.toml` to enable the swap partition. That flag is needed to allow the container to run correctly under your local docker server.

---

<div class="post-metadata">

**Author:** ![scottohara](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/scottohara/32/5202_2.png) [@scottohara](https://community.fly.io/u/scottohara)\
**Post date:** [November 3, 2022, 12:41am UTC](https://community.fly.io/t/swap-memory/2749/3 "2022-11-03T00:41:14Z")

</div>

I realise this is now an old thread, but recently I was struggling to get a Rails app to reliably run on Alpine in a standard 256Mb fly VM, and after following the advice given here to add swap, the app has been running perfectly.

Now that it’s working, I’d like to understand a bit more about the specific formula used here to calculate the size of the swapfile (just to satisfy my own curiosity).

Apologies if I get some of the Bash / POSIX terminology wrong here.

Breaking it down:

`fallocate -l <length in bytes> _swapfile`

- `fallocate` allocates space on disk
- `-l <length>` is the number of bytes to allocate
- `_swapfile` is the file name to assign to the allocated space

The length argument comes from the result of an arithmetic expansion (double parentheses), i.e. `$(( ))`.

The arithmetic expression comes from the output of another (non-arithmetic) expansion, `$( )`.

The command in _that_ subshell is:

`stat -f -c <format> .`

- `stat` displays file or filesystem status
- `-f` indicates that we’re interested in the filesystem (not file) status
- `-c <format>` specifies a format for the output
- `.` is the current directory

Finally, the format itself is:

`"(%a*%s/10)*7"`

- `%a` is the number of free blocks available to non-superuser
- `%s` is the block size (e.g. 4096)
- `10` is a constant
- `7` is a constant

…which can be rewritten as:

`( <free blocks> * <block size> / 10 ) * 7`

`<free blocks> * <block size>` obviously computes the total amount of free space (in bytes) available.

Am I right in assuming that the subsequent division by 10 and multiplication by 7 is simply a way of saying:

> please allocate 70% of all remaining available space for swap

And I’m guessing that reasons for allocating a percentage of remaining available space (as opposed to allocating a fixed value, such as `fallocate -l 512MB`) are:

1. Removes the risk of not having enough space left to allocate (assuming that `fallocate` will fail if the specified length exceeds available free space)
2. Unused disk space in containers is basically wasted, so might as well use most of it for swap? (especially for web servers/apps that don’t write much, if anything, to disk after booting)

I suppose the only downside is that, since this has to be one of the last lines in the `Dockerfile` (as it needs to calculate available space _after_ all of the code & dependencies are copied, that layer can’t be cached?

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [November 3, 2022, 1:00am UTC](https://community.fly.io/t/swap-memory/2749/4 "2022-11-03T01:00:16Z")

</div>

FYI, if people run `fly launch` on a Rails app these days, they get the following:

> <https://github.com/superfly/flyctl/blob/72736560d1a4119317dc18bb8913ab9a4d4d755b/scanner/templates/rails/standard/lib/tasks/fly.rake#L24-L36>

In other words, no formula, just a fixed size. One that can be tailored.

---

<div class="post-metadata">

**Author:** ![mathiasn](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/mathiasn/32/35151_2.png) [@mathiasn](https://community.fly.io/u/mathiasn)\
**Post date:** [May 3, 2023, 4:45pm UTC](https://community.fly.io/t/swap-memory/2749/5 "2023-05-03T16:45:05Z")

</div>

> [@OldhamMade](#):
>
> `CMD if [[! -z "$SWAP"]]; then fallocate -l $(($(stat -f -c "(%a*%s/10)*7" .))) _swapfile && mkswap _swapfile && swapon _swapfile && ls -hla; fi; free -m; /app/run`

I was trying with this one but get the following error  
**swapon: \_swapfile: Operation not permitted**

```auto
May 3 09:09:48 8c673ca3 vector Preparing to run: `/bin/sh -c if [[! -z "$SWAP"]]; then fallocate -l $(($(stat -f -c "(%a*%s/10)*7" .))) _swapfile && chmod 0600 _swapfile && mkswap _swapfile && swapon _swapfile && ls -hla; fi; free -m; /app/bin/my_app start` as nobody
May 3 09:09:48 8c673ca3 vector 2023/05/03 16:09:48 listening on [fdaa:0:5db0:a7b:13f:8c67:3ca3:2]:22 (DNS: [fdaa::3]:53)
May 3 09:09:48 8c673ca3 vector Setting up swapspace version 1, size = 5479625108 bytes
May 3 09:09:48 8c673ca3 vector UUID=5eee0e55-475f-4b1f-894d-f06ddb1a3453
May 3 09:09:48 8c673ca3 vector swapon: _swapfile: Operation not permitted
              total used free shared buff/cache available
May 3 09:09:48 8c673ca3 vector Mem: 473 16 435 0 22 445
May 3 09:09:48 8c673ca3 vector Swap: 0 0 0

```

Does it still work on your end @scottohara @OldhamMade ?

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [May 3, 2023, 5:35pm UTC](https://community.fly.io/t/swap-memory/2749/6 "2023-05-03T17:35:27Z")

</div>

> [@mathiasn](#):
>
> `as nobody`

This script needs to be run as root. You will need to remove `USER` statements from your Dockerfile (or end with `USER root`), and modify your script to test for root, setup the swapfile, change to `nobody`, and re-run the script to complete the remainder of the setup.

This sounds complicated, but it is made much clearer with an example: [rails swap](https://github.com/rubys/dockerfile-rails/blob/main/test/results/swap/docker-entrypoint). Change line 11 from `rails` to `nobody`. Replace lines 14 on with the remainder of your scirpt.

---

<div class="post-metadata">

**Author:** ![scottohara](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/scottohara/32/5202_2.png) [@scottohara](https://community.fly.io/u/scottohara)\
**Post date:** [May 3, 2023, 10:50pm UTC](https://community.fly.io/t/swap-memory/2749/7 "2023-05-03T22:50:16Z")

</div>

It’s a while ago now, but I recall struggling with similar permission issues; and in my case I solved it a slightly different way (which works for me, but has some limitations that may not work for your use case).

In my Dockerfile, I have the `fallocate`, `chmod` and `mkswap` commands as one of the first image build steps, e.g.

```auto
FROM ruby:${RUBY_VERSION}-alpine

RUN \
	fallocate -l 512M /swapfile; \
	chmod 0600 /swapfile; \
	mkswap /swapfile;

```

Then _outside_ of the Dockerfile, I have a deploy script that runs `fly deploy` followed by some `fly ssh console` commands to configure the swapfile _on the running container_, e.g.

```auto
# Deploy
fly deploy --app <our app> --build-arg <arg1> --build-arg <argN>

# Configure swap
fly ssh console --command 'sysctl --write vm.swappiness=10'

# Enable swap
fly ssh console --command 'swapon /swapfile'

```

I found that trying to set the “swappiness” level and run “swapon” as image build steps (i.e. using `RUN`) doesn’t work; and I didn’t want to change my image’s default `CMD` or `ENTRYPOINT` to run as root.

The limitation of this approach is that if you run more that one instance of the app (scale \> 1); then you would need to enable swap on every instance; and if an instance is killed and respawns, the new instance won’t have swap enabled.

In my case, I’m only running at a scale of 1 and its a non-critical app, so I can live with these limitations.

I think @rubys suggestion is probably the correct way; but if I understand correctly it does require you to run your containers with root privileges, which we understand is not generally recommended if security is a concern.

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [May 3, 2023, 10:59pm UTC](https://community.fly.io/t/swap-memory/2749/8 "2023-05-03T22:59:06Z")

</div>

> [@scottohara](#):
>
> I understand correctly it does require you to run your containers with root privileges, which we understand is not generally recommended if security is a concern.

While the script runs initially with root privileges, once swap is set up it switches users and your deployed app will be run under the unprivileged user.

---

<div class="post-metadata">

**Author:** ![evanferrao](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/evanferrao/32/12099_2.png) [@evanferrao](https://community.fly.io/u/evanferrao)\
**Post date:** [May 8, 2023, 2:21pm UTC](https://community.fly.io/t/swap-memory/2749/9 "2023-05-08T14:21:26Z")

</div>

This worked for me, Thanks.  
btw, I executed the fallocate, chmod and mkswap commands in the ssh console itself.  
`fly ssh console --command 'fallocate -l 512M /swapfile'`  
`fly ssh console --command 'chmod 0600 /swapfile'`  
`fly ssh console --command 'mkswap /swapfile'`  
`fly ssh console --command 'sysctl -w vm.swappiness=10'`  
`fly ssh console --command 'swapon /swapfile'`

I was wondering whether swap space constitutes towards the persistent storage or not? maybe @rubys would know.

---

<div class="post-metadata">

**Author:** ![Elder](https://avatars.discourse-cdn.com/v4/letter/e/3e96dc/32.png) [@Elder](https://community.fly.io/u/Elder)\
**Post date:** [May 8, 2023, 2:40pm UTC](https://community.fly.io/t/swap-memory/2749/10 "2023-05-08T14:40:12Z")

</div>

@rubys, Please consider adding a swap option to the official Fly’s [Phoenix dockerfile](https://github.com/superfly/flyctl/blob/master/scanner/templates/phoenix/Dockerfile). I couldn’t open an issue on github as you suggested [here](https://community.fly.io/t/what-is-the-correct-way-to-set-swap-for-an-app/11627/12) since its rules requrie to post requests only on the forum.

---

<div class="post-metadata">

**Author:** ![pebbletech](https://avatars.discourse-cdn.com/v4/letter/p/d6d6ee/32.png) [@pebbletech](https://community.fly.io/u/pebbletech)\
**Post date:** [August 14, 2023, 8:08am UTC](https://community.fly.io/t/swap-memory/2749/11 "2023-08-14T08:08:36Z")

</div>

Just realise there is a swap memory option in `fly.tml` which I used and check using `free -m` does setup swap correctly: [Fly Launch configuration (fly.toml) · Fly Docs](https://fly.io/docs/reference/configuration/#swap_size_mb-option)

---

<div class="post-metadata">

**Author:** ![Elder](https://avatars.discourse-cdn.com/v4/letter/e/3e96dc/32.png) [@Elder](https://community.fly.io/u/Elder)\
**Post date:** [August 14, 2023, 8:13am UTC](https://community.fly.io/t/swap-memory/2749/12 "2023-08-14T08:13:07Z")

</div>

> [@pebbletech](#):
>
> Just realise there is a swap memory option in `fly.tml` which I used and check using `free -m` does setup swap correctly: [Fly Launch configuration (fly.toml) · Fly Docs](https://fly.io/docs/reference/configuration/#swap_size_mb-option)

Interesting, did I miss an announcement about it?

PS. I check flyctl sources on github, it seems this option has been added only 3 weeks ago

---

<div class="post-metadata">

**Author:** ![madhums](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/madhums/32/14853_2.png) [@madhums](https://community.fly.io/u/madhums)\
**Post date:** [March 6, 2024, 12:20pm UTC](https://community.fly.io/t/swap-memory/2749/13 "2024-03-06T12:20:11Z")

</div>

Can anyone confirm if setting the below in `fly.toml`

```toml
swap_size_mb = 512

```

is the same as (as described [in the docs](https://fly.io/docs/rails/cookbooks/deploy/#enabling-swap))

```sh
fallocate -l 512M /swapfile
chmod 0600 /swapfile
mkswap /swapfile
echo 10 > /proc/sys/vm/swappiness
swapon /swapfile
echo 1 > /proc/sys/vm/overcommit_memory

```

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [March 6, 2024, 4:20pm UTC](https://community.fly.io/t/swap-memory/2749/14 "2024-03-06T16:20:03Z")

</div>

Doesn’t look like it `echo 1 > /proc/sys/vm/overcommit_memory` is done, but the rest are the same.

---

<div class="post-metadata">

**Author:** ![tj1](https://avatars.discourse-cdn.com/v4/letter/t/22d042/32.png) [@tj1](https://community.fly.io/u/tj1)\
**Post date:** [March 6, 2024, 4:32pm UTC](https://community.fly.io/t/swap-memory/2749/15 "2024-03-06T16:32:24Z")

</div>

> [@rubys](#):
>
> Doesn’t look like it `echo 1 > /proc/sys/vm/overcommit_memory` is done, but the rest are the same.

Sentence doesn’t parse for me. Did you mean?

> [@](#):
>
> Doesn’t look like it.  
> `echo 1 > /proc/sys/vm/overcommit_memory` is NOT done, but the rest are the same.
