Deploying Sharp Apps
Gist or GitHub App Server Deployments
As Sharp Apps are just .NET Core Web Apps, the same App can be run within a Chromium Desktop App with app, cross-platform on Windows, macOS or Linux with x in the preferred browser or hosted on a server where it's accessible to everyone with an internet connection.
Not only does not needing to compile Sharp Apps dramatically simplify App development but it also dramatically simplifies App deployment where you can completely skip all CI and build steps as there's nothing to build or deploy with the built-in support for Gist publishing.
All that's required is to run the App on your server with x open <app>
, e.g. to run redis
Gist App:
$ x open redis
Which runs on port 5000
by default, you can run it under your preferred domain by configuring nginx below.
Or to "install" the Gist App (without launching it with "open") so it can be run offline locally:
$ x install redis
Deploying Sharp Apps to Ubuntu
A common way for reliably hosting .NET Core Apps on Ubuntu is to use supervisor
to monitor the dotnet
self-hosting processes behind an nginx reverse proxy which handles external HTTP requests to
your website and proxies them to the dotnet process running your Web App on a local port. You'll need access to a Unix
environment on your client Desktop, either using Linux, OSX or
Installing Windows Subsystem for Linux (WSL).
Setup the deploy User Account
Using a Unix command-line or Windows Subsystem for Linux (WSL) ssh into your remote server:
$ ssh deploy@web-apps.io
We'll start by creating a dedicated user account for hosting and running your .NET Core Apps to mitigate potential abuse.
SSH into your Ubuntu server and create the deploy
user account with a /home/deploy
home directory and add
them to the sudo
group:
sudo useradd -m deploy
sudo usermod -aG sudo deploy
For seamless deployments use visudo
to allow deploy
to run supervisorctl
without
prompting for a password:
# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) ALL
%deploy ALL=NOPASSWD: /usr/bin/supervisorctl, /home/deploy/.dotnet/tools/x
In vi type
i
to start editing a file andESC
to quit edit mode and:wq
to save your changes before exiting.
Install the dotnet x
tool:
$ dotnet tool install -g x
For simplifying the one-time setup, it's easier to sign-in as super user:
$ sudo su -
Configure Nginx
To configure your App quickly you can start with nginx and supervisor config templates using the mix dotnet tool:
$ x mix nginx supervisor-sharp -name redis
Where after confirming, will write the config files to the appropriate locations:
Write files from 'nginx' https://gist.github.com/gistlyn/38a125eede8228ddf40651e2529a5c70 to:
/etc/nginx/sites-available/redis.web-app.io
Proceed? (n/Y):
Writing files from 'supervisor-sharp' https://gist.github.com/gistlyn/2db295508517a4eed59906320e95d98a to:
/etc/supervisor/conf.d/app.redis.conf
Then to modify the virtual host configuration of the App, change into the nginx virtual host directory:
$ cd /etc/nginx/sites-available/
and rename redis.web-app.io
file to the domain you want it hosted on instead, e.g:
$ mv redis.web-app.io redis.your-domain.com
You'll also need to rename the virtual host in the config file, which in vi you can do with:
:%s/redis.web-app.io/redis.your-domain.com/g
Which should now look something like:
server {
listen 80;
server_name redis.your-domain;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_ignore_client_abort off;
proxy_intercept_errors on;
client_max_body_size 500m;
}
}
You'll also need to update the port number if you want to run your .NET Core App on a different port.
Now to enable the site in nginx, link it with:
$ ln -s /etc/nginx/sites-available/redis.your-domain.com /etc/nginx/sites-enabled/redis.your-domain.com
Then reload nginx to pick up changes:
$ /etc/init.d/nginx reload
And voila! your Gist Sharp App is now being served at redis.your-domain.com
Configure Supervisor
We'll then configure supervisord to further harden the .NET Core App process by having it run under a managed process,
by creating a deploy User Account and giving it
permission to run the supervisorctl
and x
programs, then change directory to:
$ cd /etc/supervisor/conf.d
Where we can further modify the supervisor config file created in the mix tool, where in most cases you'll only need to change the port number if you've selected a different port in your nginx virtual host:
[program:app-redis]
command=/home/deploy/.dotnet/tools/x run redis --release
directory=/home/deploy/.sharp-apps/redis
autostart=true
autorestart=true
stderr_logfile=/var/log/app-redis.err.log
stdout_logfile=/var/log/app-redis.out.log
environment=ASPNETCORE_ENVIRONMENT=Production,ASPNETCORE_URLS="http://*:5000/"
user=deploy
stopsignal=INT
The --release flag overrides debug in app.settings so it's always run in release mode.
After reviewing the changes, tell supervisor to register and start the supervisor process with:
$ supervisorctl update
Where your website will now be up and running under a managed process at: redis.your-domain.com
Deploy Updates
Now that's everything's configured, deploying app updates are easily done by installing the app again (which downloads the latest version), then restarting the supervisor managed process, in these 2 commands:
$ x install redis
$ supervisorctl restart app-redis
Which can also be deployed from the Windows Command Prompt using a remote SSH command by combining the above commands in a deploy-redis.sh
text file:
ssh -t deploy@web-app.io "sudo /home/deploy/.dotnet/tools/x install redis && sudo supervisorctl restart app-redis"
Where App updates can then be performed with a single WSL bash command from the Windows Command Prompt:
$ bash deploy-redis.sh
Customized App Settings
If you need to customize the App's settings, like we've needed to do with blog.web-app.io app.settings to replace its OAuth keys, you can add a modified copy in its App folder which will take precedence over the read-only gist version:
$HOME/.sharp-apps/blog/app.settings
Hosted Gist Apps
All our Gist Apps are now hosted this way, by running a locally downloaded Gist App that's hosted at the following URLs:
- redis.web-app.io
- chat.web-app.io
- blog.web-app.io
- plugins.web-app.io
- spirals.web-app.io
- bare.web-app.io
Using Travis CI to deploy using Docker to AWS ECS
A popular combination for deploying .NET Core Apps is to use the online Travis CI Continuous Integration Service to package your App in a Docker Container and deploy it to AWS ECS which takes care of the management and deployment of Docker instances over a configured cluster of EC2 compute instances.
The easiest way to set this up is to clone the rockwind-aws Web App which is preconfigured with a working scripts using Travis CI to package the Web App in a Docker container and deploy it to AWS ECS. In your local copy replace the /app folder with your App files, e.g:
Dockerfile
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
COPY app /app
WORKDIR /app
RUN dotnet tool install -g x
# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS runtime
WORKDIR /app
COPY --from=build /app app
COPY --from=build /root/.dotnet/tools tools
ENV ASPNETCORE_URLS http://*:5000
ENTRYPOINT ["/app/tools/x", "app/app.settings"]
The only other file that needs to change is deploy-envs.sh to configure it to use your App's deployment settings:
deploy-envs.sh
#!/bin/bash
# set environment variables used in deploy.sh and AWS task-definition.json:
export IMAGE_NAME=netcoreapps-rockwind-aws
export IMAGE_VERSION=latest
export AWS_DEFAULT_REGION=us-east-1
export AWS_ECS_CLUSTER_NAME=default
export AWS_VIRTUAL_HOST=rockwind-aws.web-app.io
# set any sensitive information in travis-ci encrypted project settings:
# required: AWS_ACCOUNT_ID, AWS_ACCESS_KEY, AWS_SECRET_KEY
# optional: SERVICESTACK_LICENSE
Setup AWS ECS and Travis CI
After configuring your App deployment scripts you'll then need to Setup your AWS ECS with an EC2 instance to deploy to and Create your project in Travis CI. You'll then need to add your AWS Account details in the Travis CI project using Secure Environment Variables to store your AWS_ACCOUNT_ID, AWS_ACCESS_KEY and AWS_SECRET_KEY as well as any sensitive info and connection strings your App uses.