16

I would like to run a .NET Core MVC website from an AWS Amazon Linux AMI instance.

Here are the steps I have taken so far:

  1. Create a template ASP.NET Core Web Application (.NET Core) - C# - MVC Web Application project in Visual Studio 2015. Compile and run application in IIS Express. No changes made to any configuration (web.confg, project.json, etc).
  2. Upload entire web application solution to GitHub.
  3. Launch an Amazon Linux AMI (2016.03.2) instance. Security Group has "all traffic" access open for now for simplicity.
  4. Use PuTTY to SSH into Linux instance. Log in with ec2-user.
  5. Update the instance sudo yum update -y
  6. Install libunwind sudo yum install libunwind -y
  7. Install gettext sudo yum install gettext -y
  8. Install .NET Core curl -sSL https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-preview1/scripts/obtain/dotnet-install.sh | bash /dev/stdin --version 1.0.0-preview1-002702 --install-dir ~/dotnet
  9. Link sudo ln -s ~/dotnet/dotnet /usr/local/bin
  10. Install .NET Version Manager (DNVM) curl -sSL https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.sh | DNX_BRANCH=dev sh && source ~/.dnx/dnvm/dnvm.sh
  11. Run command source /home/ec2-user/.dnx/dnvm/dnvm.sh
  12. Install .NET Execution Environment (DNX) dnvm upgrade -r coreclr
  13. Install libuv to be used by Kestrel sudo yum install automake libtool wget -y wget http://dist.libuv.org/dist/v1.8.0/libuv-v1.8.0.tar.gz tar -zxf libuv-v1.8.0.tar.gz cd libuv-v1.8.0 sudo sh autogen.sh sudo ./configure sudo make sudo make check sudo make install sudo ln -s /usr/lib64/libdl.so.2 /usr/lib64/libdl sudo ln -s /usr/local/lib/libuv.so.1.0.0 /usr/lib64/libuv.so
  14. Install Git sudo yum install git -y
  15. Create directory in '/home/ec2-user' directory for application. Move to that directory. mkdir director-name cd directory-name
  16. Clone web app with Git git config user.name "myUserName" git config user.email "myEmail" git clone https://github.com/username/repositoryname.git
  17. Move to 'project' directory cd solution-name/src/web-project-name.
  18. Restore packages dotnet restore
  19. Build application dotnet build
  20. Run application dotnet run

At this point I see the following in the terminal:

Now listening on: http ://localhost:5000

I attempt to hit the AWS DNS/IP with port 5000 tagged at the end (http ://aws-ip-or-dns:5000), but get no response.

I know that Docker and Mono are tools that I can use, but I would rather get this approach to work.

The scripts I used to install .NET Core, DNVM, and DNX are some combination of the CentOS and Ubuntu directions from these links:

  1. https://docs.asp.net/en/latest/getting-started.html
  2. https://www.microsoft.com/net/core#centos
  3. https://docs.asp.net/en/1.0.0-rc1/getting-started/installing-on-linux.html

Disclaimer I am not that experienced with Linux. It is fair to say I don't understand some of the commands that I'm running. But, I'm here to learn!

Question: What do I need to do to get a template .NET Core web application running an an AWS Amazon Linux environment?

(My guess is I have something missing with setting up the HTTP server)

I need more reputation to post more than two links, so if someone wants to EDIT, I'd appreciate it.

DavidG
  • 113,891
  • 12
  • 217
  • 223
Bruno L.
  • 391
  • 8
  • 16
  • Is there a firewall in place? Do you have access to port 500 through it? Perhaps try port 80 instead. – DavidG Jun 22 '16 at 17:18
  • @DavidG No, there is not a firewall in place. With AWS instances, Security Groups can be used to limit access to ports, but there are no limitations in place. Trying port 80 has the same _connection refused_ error. – Bruno L. Jun 22 '16 at 17:23
  • 1
    Does that URL work locally on the box? Perhaps try with `curl`? e.g. `curl http ://localhost:5000` – DavidG Jun 22 '16 at 17:24
  • @DavidG You would have to explain in more detail what I should do with "curl" to hit the URL locally. Also, when the app is running, it looks like I can't enter other commands until I stop the app with Ctrl+C. – Bruno L. Jun 22 '16 at 17:28
  • Connect with another SSH window and run `curl http://localhost:5000` – DavidG Jun 22 '16 at 17:30
  • @DavidG Thanks. That did work. On the terminal running the application, there was some action (GET request, Execute blah-blah). And on the other terminal, I got a dump of the HTML for the "Home" page. – Bruno L. Jun 22 '16 at 17:33
  • So it looks like either there is a firewall (locally to the server or remote) or if you are sure there isn't one, then it could be that the app is only binding to the localhost address (127.0.0.1) instead of the public IP. – DavidG Jun 22 '16 at 17:37
  • @DavidG Only binding to the localhost address seems more likely. I have a "hosting.json" file in the project directory where I defined the public IP, but that didn't help. Any ideas where to configure the binding to the public IP? – Bruno L. Jun 22 '16 at 17:44
  • Can you change the `server.urls` parameter to be `"http://0.0.0.0:5000"`? – DavidG Jun 22 '16 at 17:46
  • Changed, build project again, same result. – Bruno L. Jun 22 '16 at 17:51
  • Hmm if you change that to `http://0.0.0.0:5001`, does curl now work with port 5001 instead? You shouldn't need to rebuild anything, just edit file and re-run the app. – DavidG Jun 22 '16 at 17:53
  • Or even starting the app with `dotnet run --server.urls=http://0.0.0.0:5000`? – DavidG Jun 22 '16 at 17:55
  • @DavidG The curl command works for 0.0.0.0, but still can't access from a web browser. Starting the app with the parameters has the same result. I'm currently looking at this post to see if it has something helpful http://stackoverflow.com/questions/34212765/how-do-i-get-the-kestrel-web-server-to-listen-to-non-localhost-requests – Bruno L. Jun 22 '16 at 18:01
  • How about with port 5001 specified? – DavidG Jun 22 '16 at 18:02
  • Or perhaps your Amazon security groups need reviewing? Have you specified that port 5000 is allowed? – DavidG Jun 22 '16 at 18:04
  • @DavidG All Traffic, on All Protocols, on All Port Ranges are allowed. No restrictions. Inbound and Outbound. – Bruno L. Jun 22 '16 at 18:08
  • Every get a soultion to this im getting the same problem – AJ_ Sep 07 '16 at 16:42

4 Answers4

5

The answer from @user326608 almost gets it there, but I'm going to add the steps I am using now after the release of .NET Core 1.0.0.

  1. Create a template ASP.NET Core Web Application (.NET Core) - C# - MVC Web Application project in Visual Studio 2015. Compile and run application in IIS Express. No changes made to any configuration (web.confg, project.json, etc).
  2. Upload entire web application solution to GitHub. Do not include project.lock.json in the Git upload.
  3. Launch an Amazon Linux AMI (2016.09.0) instance. Security Group with SSH, HTTP, and HTTPS traffic allowed.
  4. Use PuTTY to SSH into Linux instance. Log in with ec2-user.
  5. Update the instance sudo yum update -y
  6. Install libunwind sudo yum install libunwind -y
  7. Download .NET Core curl -sSL -o dotnet.tar.gz https://go.microsoft.com/fwlink/?LinkID=809131
  8. Install .NET Core sudo mkdir -p /opt/dotnet && sudo tar zxf dotnet.tar.gz -C /opt/dotnet
  9. Link sudo ln -s /opt/dotnet/dotnet /usr/local/bin
  10. Configure IP tables sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 5000
  11. Install Git sudo yum install git -y
  12. Configure git config --global user.name "myUserName"
  13. Configure git config --global user.email "myGitEmail@something.com"
  14. Make directory mkdir /var/coreapp
  15. Move to directory cd /var/coreapp
  16. Get project from Git git clone https://github.com/myUsername/myRepository.git
  17. Change owner sudo chown -R ec2-user /var/coreapp
  18. Move to direcotry cd /var/coreapp/solution-name/src/web-project-name
  19. Restore dotnet restore, build dotnet build, and run in background nohup dotnet run > /dev/null 2>&1 &

This solution is working well for me now. I have a related post trying to create a User Data bootstrap script to try and make this even easier.

Community
  • 1
  • 1
Bruno L.
  • 391
  • 8
  • 16
1

For anyone needing to update the above for the Microsoft.NETCore.App 1.0.1 September 2016 update, the https://www.microsoft.com/net/core#centos instructions worked for me:

curl -sSL -o dotnet.tar.gz https://go.microsoft.com/fwlink/?LinkID=827529
sudo mkdir -p /opt/dotnet && sudo tar zxf dotnet.tar.gz -C /opt/dotnet
sudo rm /usr/local/bin/dotnet
sudo ln -s /opt/dotnet/dotnet /usr/local/bin

Subsequently running dotnet --info gives:

.NET Command Line Tools (1.0.0-preview2-003131)

Product Information:
 Version:            1.0.0-preview2-003131
 Commit SHA-1 hash:  635cf40e58

Runtime Environment:
 OS Name:     amzn
 OS Version:  2016.09
 OS Platform: Linux
 RID:         amzn.2016.09-x64

After that I deleted my project.lock.json and ran a dotnet restore.

I couldn't get a dotnet run to work directly as my RID wasn't known, but using a Dockerfile with microsoft/dotnet:onbuild and this section in my project.json worked:

"runtimes": {
    "debian.8-x64" : {}
},
user326608
  • 2,210
  • 1
  • 26
  • 33
  • 1
    The debian RID you've used here should also work as an argument to a `dotnet publish` command to create a published artifact for the dotnet `core` docker image. – GrandOpener Oct 25 '16 at 01:04
0

If you are running your AWS instance in VPC mode and you don't have security group that says that it's inbound rule has "All Traffic" and Source is "Anywhere" or if it says that "Custom TCP rule", Port is 5000 and Source is "Anywhere" then it will not allow you to connect to that port. In VPC mode all incoming ports are closed by default and you should allow them explicitly with some predefined or your own security groups.

Sergey Kuznetsov
  • 518
  • 4
  • 10
  • 1
    This is not the issue. Point #3 of the question states that I have a Security Group with "All Traffic" for the EC2 instance. The problem was not with AWS, but with how the web project was configured. – Bruno L. Sep 01 '16 at 14:42
0

If you use Opswork (or Chef) you can use the following Chef recipe https://supermarket.chef.io/cookbooks/dotnetcore to install a dotnet core on AWS Linux, assumption are that you have uploaded the a zipped file using dotnet publish file to a S3 bucket.
The layer json has JSON that has the app short name e.g.

{
  myapp {}
}

# The recipe to install
# 1) Figure which App needs to be installed using JSON in Opsworks layer
# 2) Get the Zip file from S3 and Unzip into /usr/bin/myapp/publish
# 3) Create bash file to start
# 4) Start the app 

    apps = search(:aws_opsworks_app)
    apps.sort_by { |v| v["shortname"] }.each do |app|
        appname = app["shortname"]
        app_source = app["app_source"]
        bucket, remote_path = OpsWorks::SCM::S3.parse_uri("#{app_source['url']}")
        filename = remote_path.split("/")[-1]
        extn = File.extname  filename
        if (!node["#{appname}"].nil? && extn == '.zip')
            apppath = "/usr/bin/#{appname}"
            dotnetapp = app["environment"]["dotnetapp"]
            aspnetcore_environment = app["environment"]["aspnetcore_environment"]
            Chef::Log.info("App dotnet Name:#{app[:environment][:dotnetapp]}")
            Chef::Log.info("Enviroment:#{aspnetcore_environment}")


            app_checkout = ::File.join(Chef::Config["file_cache_path"], app["shortname"])

            package = "#{app_checkout}/#{filename}"

# Use https://github.com/awslabs/opsworks-windows-demo-cookbooks or any s3_file recipe to download the zip file
# if you copy the opsworks-windows-cookbooks you will to modify the recipe a little to work on aws linux
            opsworks_scm_checkout app["shortname"] do
                destination      app_checkout
                repository       app_source["url"]
                user             app_source["user"]
                password         app_source["password"]
                type             app_source["type"]
                ssh_key          app_source["ssh_key"]
                revision         app_source["revision"]
            end


            directory "#{apppath}" do
            end

            execute 'unzip package' do
                command "unzip -o #{app_checkout}/#{filename} -d #{apppath}"

            end

            # create a sysvint sh file to manage dotnet service 
            initd_directory = "/etc/init.d"

            intd_file = File.join(initd_directory, app["shortname"])

            template intd_file do
                mode "744"
                source 'file.sh.erb'
                variables(
                    :service_name => app["shortname"],
                    :dotnetapp => "#{dotnetapp}",
                    :apppath => "#{apppath}/publish"
                )
            end
            execute "start service #{dotnetapp}" do
                command ".#{initd_directory}/#{appname} start"
                environment ({"ASPNETCORE_ENVIRONMENT" => "#{aspnetcore_environment}"})
            end
            Chef::Log.info("End Install #{appname}")
        end
    end

# The ERB Template:

#!/bin/bash
#
# description: <%= @service_name %>
#

# Get function from functions library
. /etc/init.d/functions
#
# Start the service <%= @service_name %>
#
start() {
        initlog -c "echo -n Starting dotnet <%= @service_name %> server: "
        cd <%= @apppath %>
        nohup dotnet <%= @dotnetapp %> /dev/null 2>&1 &
        ### Create the lock file ###
        touch /var/lock/subsys/<%= @service_name %>
        success $"<%= @service_name %> server startup"
        echo
}

# Restart the service <%= @service_name %>
stop() {
        initlog -c "echo -n Stopping dotnet <%= @service_name %> server: "
        killproc dotnet
        ### Now, delete the lock file ###
        rm -f /var/lock/subsys/<%= @service_name %>
        echo
}

### main logic ###
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  status)
        status dotnet
        ;;
  restart|reload|condrestart)
        stop
        start
        ;;
  *)
        echo $"Usage: $0 {start|stop|restart|reload|status}"
        exit 1
esac

exit 0 
Haroon
  • 1,052
  • 13
  • 28