javaamazon-web-servicesamazon-elastic-beanstalknanohttpd

How to host nanohttpd java app on AWS?


I've wrote simple hello-world http server app with nanohttpd:

package name.antonsmirnov.apptogether.service.http;

import fi.iki.elonen.NanoHTTPD;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * HTTP server
 */
public class HttpSample {

    private static Logger logger = LoggerFactory.getLogger(HttpSample.class);

    private NanoHTTPD server;
    private int port;
    private String host;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    private AtomicInteger counter = new AtomicInteger(0);

    private void initHttp() {
        server = new NanoHTTPD(host, port) {
            @Override
            public Response serve(IHTTPSession session) {
                String ip = session.getHeaders().get("http-client-ip");
                logger.info("Request from " + ip);
                String message = "hello " + ip + " " + counter.incrementAndGet();
                return newFixedLengthResponse(Response.Status.OK, MIME_PLAINTEXT, message);
            }
        };
    }

    /**
     * Start HTTP server
     * @throws Exception
     */
    public void start() throws Exception {
        if (started)
            return;

        initHttp();
        started = true;

        doStart();
    }

    private void doStart() throws IOException {
        logger.info("Starting at port {} ...", port);
        server.start();
        logger.debug("Started");
    }

    /**
     * Stop HTTP server
     * @throws Exception
     */
    public void stop() throws Exception {
        if (!started)
            return;
        started = false;

        doStop();
    }

    private void doStop() {
        logger.info("Stopping ...");
        server.stop();
        logger.debug("Stopped");
    }

    private boolean started;

    public boolean isStarted() {
        return started;
    }

    public static void main(String[] args) {
        HttpSample httpSample = new HttpSample();
        httpSample.setPort(5555);
        httpSample.setHost("0.0.0.0");

        try {
            httpSample.start();
        } catch (Exception e) {
            logger.error("Failed to start", e);
            return;
        }

        try {
            Thread.sleep(Long.MAX_VALUE);
        } catch (InterruptedException e) {
            logger.error("Interrupted");
        }
    }
}

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>name.antonsmirnov.apptogether</groupId>
    <artifactId>http-sample</artifactId>
    <version>1.0</version>
    <description>HTTP server</description>

    <dependencies>

        <!-- http server -->
        <dependency>
            <groupId>org.nanohttpd</groupId>
            <artifactId>nanohttpd</artifactId>
            <version>2.2.0</version>
        </dependency>

        <!-- logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.6.1</version>
        </dependency>

        <!-- logging -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.0.13</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <archive>
                                <manifest>
                                    <mainClass>name.antonsmirnov.apptogether.service.http.HttpSample</mainClass>
                                </manifest>
                            </archive>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

after maven clean package i'm able to run it locally with java -jar ...-with-dependencies.jar and i can navigate to 127.0.0.1:5555 and see response.

When i host it on AWS Elastic Beanstalk as "web tier"

enter image description here

i can see it's started in logs:

-------------------------------------
/var/log/nginx/error.log
-------------------------------------
2018/06/06 19:34:57 [error] 3230#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 5.189.7.39, server: , request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:5000/", host: "http.us-east-2.elasticbeanstalk.com"
2018/06/06 19:34:58 [error] 3230#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 5.189.7.39, server: , request: "GET /favicon.ico HTTP/1.1", upstream: "http://127.0.0.1:5000/favicon.ico", host: "http.us-east-2.elasticbeanstalk.com", referrer: "http://http.us-east-2.elasticbeanstalk.com/"



-------------------------------------
/var/log/web-1.log
-------------------------------------
19:32:58.043 [main] INFO  HttpSample - Starting at port 5555 ...
19:32:58.062 [main] DEBUG HttpSample - Started



-------------------------------------
/var/log/web-1.error.log
-------------------------------------

But it's unreachable in http://http.us-east-2.elasticbeanstalk.com:5555

I can't see requests in the log (i should be able to see smth like 00:59:25.864 [NanoHttpd Request Processor (#1)] INFO HttpSample$1 - Request from x.y.z.k like on localhost). Instead i see ERR_CONNECTION_TIMED_OUT error.

What's wrong? Should i configure ports for VPC somehow? Does it conflict with nginx?


Solution

  • I had just allow incoming requests on port 5555 in security group:

    enter image description here

    Not sure if it conflicts with nginx if i decide to use port 80 though.