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.
Running Genie apps in production mode
When run locally during development, Genie apps are in development mode. This means they include nice features such as hot-reloading of code changes, but are not optimized for perfomance. When deployed, the app should be in production mode. There are two ways to do this:
- Setting the
GENIE_ENV
environment variable toprod
before running the app from the terminal:
GENIE_ENV=prod julia --project -e "using GenieFramework; Genie.loadapp(); up(async=false);
- If you're using configuration files, edit
config/env/global.jl
and add the following line:
ENV["GENIE_ENV"] = "prod"
If you want to run multiple apps on the same machine, or want your app to be accessible at a specific path like mydomain.com/mygenieapp
, you need to configure a reverse proxy to redirect traffic to the appropriate app. See this guide to learn how to configure NGINX for this purpose.
Deploying 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"
ENV EARLYBIND "true"
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 -d
The -p 8000:8000
option binds the port 8000 at localhost to the port 8000 on the container, whereas -d
runs it in detached mode in the background.
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:
- Place the
Dockerfile
at the root of the app folder. - Run
fly launch
and follow the instructions in the terminal. - 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.
In this guide our MyGenieApp
has its code at github.com/user/MyGenieApp
.
Runing the 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()
Now, configure the secret token with the following command:
julia --project=. --banner=no --eval="using Pkg; using Genie; Genie.Generator.write_secrets_file()
This will generate a secrets.jl
file inside config/secrets.jl
, and if it exists then it will update it with a new token string.
Finally, set the prod
flag and launch the app in the background with nohup
:
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.
Troubleshooting
If the Genie app is not running on startup, you can try the following:
- Verify if the sudo systemctl status supervisor.service service is operational. If it's not working, you can start it and enable it for startup using the following commands:
sudo systemctl enable supervisor.service
sudo systemctl start supervisor.service
- To inspect the application logs, you can tail the log file as:
tail -f /var/log/genie-application.log
- Ensure that the port specified in the
GENIE_ENV
config file underserver_port
is open in the firewall and that no other process is bound to it.
For instance, to check if any process is running on port 80, do:
sudo lsof -t -i:80
If you need to terminate a process running on port 80, you can do:
if sudo lsof -t -i:80; then sudo kill -9 $(sudo lsof -t -i:80); fi
Controlling file load order
The default load sequence of Julia files inside the plugins, libs, controllers folders is alphabetical. However, sometimes you might want to control the default load order of .jl files. Let's assume we have a directory with a few of .jl files as follows
Reverse proxy
How to use NGINX as a reverse proxy to serve multiple Genie apps and improve performance.