--- title: Deploying on fly.io tags: docker, deployment, websockets --- I spent some time today deploying [uMap](https://umap-project.org) to [fly.io](https://fly.io), using a `Dockerfile`. Here are some notes I took. First, I had to install the `flyctl` command. On OSX, with `brew`, it's: ```bash brew install flyctl ``` Fly is using docker containers under the hood, and provides some tools to help create the files. In the case of uMap, I already had a `Dockerfile`, so it wasn't necessary. ## Creating an app I created an app: ```bash fly apps create ``` By answering the questions. It eventually generated a `fly.toml` file., that I actually rewrote to fit my needs: ```toml app = 'umap' primary_region = 'iad' console_command = 'umap shell' [build] dockerfile = "Dockerfile" [[services]] internal_port = 8000 protocol = 'tcp' processes = ["app"] [[services.ports]] handlers = ['http'] port = 80 force_https = true [[services.ports]] handlers = ['http', "tls"] port = 443 [[vm]] memory = '1gb' cpu_kind = 'shared' cpus = 1 ``` The `services` section could be simplified by using the `http_service` section, but as I will need to configure websockets on a different port, it seems to be a better bet. ## Creating PostgreSQL / PostGIS database I created a postgres app, that I named `postgres_umap` by answering the questions asked by this command: ```bash flyctl postgres create ``` Then I had to activate the PostGIS extension, by connecting to the postgres cluster… ```bash flyctl postgres connect -a postgres-umap ``` … and enter this: ``` CREATE EXTENSION postgis ``` At this stage, the machine crashed, and a `fly logs -a postgres-umap` told me that it was out of memory. I bumped the memory a bit with this: ```bash # got the id of the machine with fly machine status -a postgres-umap # and then bumped the memory to 1024mb fly machine update 3d8dd964a25978 --vm-memory 1024 --app postgres-umap ``` Redoing the `CREATE EXTENSION postgis;` worked this time. Once this is done, I used this utility: ```bash fly postgres attach postgres-umap --app umap ``` This created users, passwords and a database for me, and set the proper secrets for my app. Neat. I received an email telling me this costs money, so after initializing the postgis database, I scaled the instance down: ```bash fly machine update 3d8dd964a25978 --vm-memory 256 --app postgres-umap ``` ## Handling secrets Additionally to environment variables (which are present in the `fly.toml` file), I also had to define some secrets, using `fly secrets`: ```bash secrets set SECRET_KEY=S0_S3CR3T ``` At some point, I had to unset some of them with: ```bash secrets unset SECRET_KEY ``` I also added a few env vars: ```toml [env] WEBSOCKET_URI = "wss://xxx.fly.dev:8001" WEBSOCKET_HOST = "0.0.0.0" WEBSOCKET_ENABLED = "True" UMAP_ALLOW_ANONYMOUS = "True" ``` ## Deploying With this in place, I could deploy these two machines with `fly deploy`. ## Adding support for WebSockets This can change in the future, but for now, I have two servers, a WebSocket server listening on port `8001`, separate from the `uwsgi` server listening on `443` and `80`. It is possible to define some specific commands that will replace the default `CMD` one of the `Dockerfile`. To do this, I used the `[processes]` section, and named the default one `django`, because it's running the django server with `uwsgi`: ```toml [processes] ws = "/venv/bin/python /venv/lib/python3.11/site-packages/umap/ws.py" django = "/srv/umap/docker/entrypoint.sh" ``` … and added a new services definition: ```toml [[services]] internal_port = 8001 protocol = 'tcp' processes = ['ws'] [[services.ports]] handlers = ['tls'] port = 8001 ``` Also, I'm not sure why I had to downgrade the number of processes: ```bash fly scale count 1 --process-group=django fly scale count 1 --process-group=ws ``` ## Using a custom domain I wanted this to be hosted on my domain, so I went with adding a `CNAME`, following [this documentation](https://fly.io/docs/networking/custom-domain/): ```bash CNAME xxx xxx.fly.dev ``` And then generated the SSL certs: ```bash fly certs add xxx.domain.tld ``` ## Persisting files Everything was working smoothly until I realize that the files weren't actually persisted. For the files to be persisted, I needed to add volumes in the toml file: ```toml [mounts] source="umap_data" destination="/srv/umap/uploads" ``` And create the volumes with the cli: ```bash fly volume create umap_data -r iad -n2 fly deploy ```