Deploying Genie apps

Deploying a Genie app online makes it easily shareable with a URL. There are many ways to do this, and this guide will cover a few of them, namely with a container or directly to a server.

Using docker

Containerization is a lightweight form of virtualization that encapsulates an application and its dependencies into a standalone, executable package. This makes apps portable and scalable, and solves the universal "it works on my machine" problem.

Docker makes container creation straightforward via its Dockerfile blueprint. Moreover, advanced workflows are possible such as including multiple containers running services such as databases or other backend services.

This Dockerfile, based on the official Julia image, can be used used to build a Genie app's container:

FROM julia:latest
RUN useradd --create-home --shell /bin/bash genie
RUN mkdir /home/genie/app
COPY . /home/genie/app
WORKDIR /home/genie/app
RUN chown -R genie:genie /home/
USER genie
RUN julia -e "using Pkg; Pkg.activate(\".\"); Pkg.instantiate(); Pkg.precompile();"
EXPOSE 8000
EXPOSE 80
ENV JULIA_DEPOT_PATH "/home/genie/.julia"
ENV JULIA_REVISE = "off"
ENV GENIE_ENV "prod"
ENV GENIE_HOST "0.0.0.0"
ENV PORT "8000"
ENV WSPORT "8000"
ENTRYPOINT ["julia", "--project", "-e", "using GenieFramework; Genie.loadapp(); up(async=false);"]

To use it, place the Dockerfile at the root of the app folder and build the image with

docker build . -t imagetag

Then, you can run the app in the container with

docker run -p 8000:8000 imagetag

The -p 8000:8000 option binds the port 8000 at localhost to the port 8000 on the container.

There exist dozens of deployment services for Docker, of which fly.io is one of the easiest to use. To deploy a Genie app on this service, install the flyctl cli and perform these steps:

  1. Place the Dockerfile at the root of the app folder.
  2. Run fly launch and follow the instructions in the terminal.
  3. Increase the computing instance's RAM with fly scale memory 1024.

The fly.io servers will build and deploy the image, making it accessible through a web address.

Deploying to a server

Prerequisites

To expose the app over the internet, one needs access to a server. This can be a local machine or a cloud instance such as AWS EC2 or a Google Cloud Compute Engine for example.

If using a local server, a static IP is needed to ensure continuous access to the app. Internet service provider generally charge a fee for such extra service.

We assume that a Genie app has been developed and is ready for deployment and that it is hosted as a project on a git repository.

We assume that a Genie app MyGenieApp has its code is hosted at github.com/user/MyGenieApp.

Install and run the Genie app on the server

Access the server:

ssh -i "ssh-key-for-instance.pem" user@123.123.123.123

Install Julia if not present. Then clone your app's code:

git clone github.com/user/MyGenieApp
cd MyGenieAp

Install the app as with any other Julia project:

julia --project
] 
pkg> instantiate
exit()

Launch the app:

nohup export GENIE_ENV=prod && julia --project -e "using GenieFramework; Genie.loadapp(); up(async=false);" &

Now the Genie app should be running on the server and be accessible at 123.123.123.123:8000(if port 8000 is open.

To launch the app on startup, you can use the supervisor utility. Install it with apt-get install supervisor, and create a genie-supervisor.conf file in the project folder with this content:

[program:genie-application]
process_name=%(program_name)s_%(process_num)02d
command=export GENIE_ENV=prod && julia --project -e "using GenieFramework; Genie.loadapp(); up(async=false);"
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/genie-application.log
stopwaitsecs=3600

Next create a symbolic link to the supervisor config file

sudo ln -s /path/to/genie-supervisor.conf /etc/supervisor/conf.d/genie-supervisor.conf
sudo /etc/init.d/supervisor reload

The next time you restart your system, the Genie app will be automatically launched.

NGINX reverse proxy

Nginx server will be used as a reverse proxy. It will listen requests made on port 80 (HTTP) and redirect traffic to the Genie app running on port 8000 (default Genie setting that can be changed).

Nginx will also be used to serve the app static files, that is, the content under the ./public folder.

Finally, it can as well handle HTTPS requests, which will also be redirected to the Genie app listening on port 8000.

First, install NGINX with:

sudo apt-get update
sudo apt-get install nginx
sudo systemctl start nginx
sudo systemctl enable nginx

A configuration file then needs to to be created to indicate on which port to listen (80 for HTTP) and to which port to redirect the traffic (8000 for the default Genie config).

Create a config file in /etc/nginx/sites-available with sudo nano my-genie-app. Then, add the following to my-genie-app:

server {
  listen 80;
  listen [::]:80;

  server_name   test.com;
  root          /home/ubuntu/MyGenieApp/public;
  index         welcome.html;

  location / {
      proxy_pass http://localhost:8000/;
  }

  location /css/genie {
      proxy_pass http://localhost:8000/;
  }
  location /img/genie {
      proxy_pass http://localhost:8000/;
  }
  location /js/genie {
      proxy_pass http://localhost:8000/;
  }
}
  • server_name: refers to the web domain to be used. It can be put to an arbitrary name if the app is only to be served directly from the server public IP.
  • root: points to the public subfolder where the genie app was cloned.
  • index: refers to the site index (the landing page).
  • The various location following the initial proxy to the genie app are used to indicate static content folders to be served by nginx. These are needed when the server_handle_static_file is set to false in the Genie app settings.

To enable the reverse proxy, add the config file to the sites-enabled with a symlink:

sudo ln -s /etc/nginx/sites-available/my-genie-app /etc/nginx/sites-enabled/my-genie-app

Then restart the server to make changes effective:

sudo systemctl restart nginx

Enabling HTTPS

To enable HTTPS, a site-certificate will be needed for the domain on which the site will be served. A practical approach is to use the utilities provided by certbot.

Following provided instructions for nginx on Ubuntu 20.04:

sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Then, using the certbot utility, a certificate will be generated and appropriate modification to NGINX config will be made to handle support for HTTPS:

sudo certbot --nginx

Note that this step will check for ownership of the test.com domain mentionned in the NGINX config file. For that validation to succeed, it requires to have the A record for the domain set to 123.123.123.123.