What you will need:
sudo
permissions<yourapp>
in the following instructions with
that name.<yourdomain>
in the following
instructions with that domain name.sudo apt install postgresql
sudo apt install git
Create a new user. This will be the user your app will run as.
sudo adduser --disabled-login deploy
This will hold your application’s code:
sudo mkdir /srv/<yourapp>
sudo chown deploy:deploy /srv/<yourapp>
Management of PostgreSQL on Debian/Ubuntu
is usually performed as the postgres
user.
Use
sudo su - postgres
to become the postgres
user and create a
new database for your app:
createdb -O deploy <yourapp>_production
Become the deploy
user:
sudo su - deploy
And then check out your code:
git clone <your_repo_url> /srv/<yourapp>
cd /srv/<yourapp>
On subsequent deployments you can then simply
use git pull
to get the latest code or
git fetch
followed by git checkout
to
check out a specific tag or branch.
Once you have the code you want to deploy you need to install / update dependencies:
yarn install
shards install
Then first compile your assets for production use:
yarn prod
And finally your lucky app:
crystal build --release src/start_server.cr
After every deploy you should run your migrations:
crystal run tasks.cr -- db.migrate
Note: You may have to specify the
DATABASE_URL
and any other environment variables your app uses before you can migrate. OnlyDATABASE_URL
needs to be real. The rest can be blank. For example if your app usesAPI_KEY
andSUPPORT_EMAIL
environment variables, you can add them before running crystal like so:API_KEY= SUPPORT_EMAIL= DATABASE_URL=postgres://<username>:<password>@127.0.0.1/<appname>_production crystal run tasks.cr -- db.migrate
Exit your session as the deploy
user, either
with CTRL-D
or by entering exit
.
If you are on your first install, we will worry about starting the server later. On subsequent deployments you will need to trigger a restart:
sudo service <yourapp> restart
Modern versions of Ubuntu use systemd
as init system and process supervisor. Systemd
can take care of starting your app and even
restarting it in case of crashes.
To start with, you could create a “unit file”
in /etc/systemd/system/<yourapp>.service
with
the following content:
[Unit]
Description=Awesome description of <yourapp>
After=nginx.service
[Service]
Type=simple
User=deploy
Environment="LUCKY_ENV=production"
Environment="SECRET_KEY_BASE=<random unique key>"
Environment="SEND_GRID_KEY=<SendGrid key>"
Environment="DATABASE_URL=postgres://<username>:<password>@127.0.0.1/<appname>_production"
Environment="HOST=127.0.0.1"
Environment="PORT=5000"
Environment="APP_DOMAIN=https://<yourdomain>"
WorkingDirectory=/srv/<yourapp>
ExecStart=/srv/<yourapp>/start_server
Restart=on-failure
[Install]
WantedBy=multi-user.target
Take special note of the environment variables:
LUCKY_ENV
This tells lucky to run in production
mode.
SECRET_KEY_BASE
This is a secret key that should be random and unique to your
server. You can use the gen.secret_key
task to generate
a suitable string:
lucky gen.secret_key
SEND_GRID_KEY
This is your SendGrid key to be able to send emails. Set it to ‘unused’ if not sending emails.
DATABASE_URL
This tells lucky where to find your database.
APP_DOMAIN
lucky uses this setting to generate full URLs.
HOST and PORT
This tells our server on which IP address and port to listen on. We set this to localhost to not expose the lucky app directly to the internet. Instead we will put a “proper” webserver in front of it, that can also handle TLS/SSL among other things.
After creating a new unit file, or editing
an existing one, you need to run the
following command for systemd
to pick
up the changes:
sudo systemctl daemon-reload
Then you should be able to start your app for the first time:
sudo service <yourapp> start
This would be a good time to further
read about systemd
s
unit files
and
service definitions
just in case you would like to make some
customizations.
Install nginx:
sudo apt install nginx
Create a new configuration file in
/etc/nginx/sites-available/<yourapp>.conf
with the following content:
upstream lucky {
server localhost:5000;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name <yourdomain>;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
root /srv/<yourapp>/public;
server_name <yourdomain>;
location / {
proxy_pass http://lucky;
}
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
}
If you keep
default_server
in config above, remove thedefault
sites config from/etc/nginx/sites-enabled
. If you intend to host your app alongside other virtual hosts and it’s not your default site then removedefault_server
from the config above.
Create a symbolic link for your configuration
in /etc/nginx/sites-enabled
:
sudo ln -s /etc/nginx/sites-available/<yourapp>.conf /etc/nginx/sites-enabled/<yourapp>.conf
Restart nginx:
sudo service nginx restart
logrotate
to rotate
it at regular intervals