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 and ESC 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:

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.

Let us know what you create!

We hope you're excited about these new features as we are and can't wait to see what you build with them - please share them with us so we can include it in the App Gallery and make it easy for everyone else to discover and use.

made with by ServiceStack