Showing posts with label cheap. Show all posts
Showing posts with label cheap. Show all posts

02 October, 2015

Hosting static websites on AWS S3

Hosting websites nowadays has become quite simple, easy and affordable.  Years ago you would try to find free hosts which would allow you to upload a few files and you're done.  GeoCities and freewebs were some of the most popular of these services.  As time went by, the data centre landscape has changed dramatically and the current situation is big companies offering extremely cheap hosting services.  The market is so huge that the classic "brochure site" has become almost free to host while still enjoying world class availability and scalability.

Static websites are the simplest form of site.  These are just a set of HTML pages linked together via links.  No complicated code, no weird configurations - just plain old files.  Depending on what you want, such a site may be ideal (maybe you do all your business transactions over a facebook page and use the site just as a brochure).



This of course has the advantage of being simple, easy, cheap and can be up and running very quickly, including development time.  It lacks, however, some of the major features you may want, such as a member's area, blogs and news, user-generated content etc.  But then again, you might not want these extra features.  In that case, here is a simple, short and sweet guide on how to host your site on Amazon Web Services.  There is no doubt that it is currently the leader in cloud services and it would be wise to use their services.

1. Get A Domain

The first thing you need is the dot-com.  You may use or favourite registrar or just randomly choose one from these that come to mind: noip.com, namecheap.com, godaddy.com.  If this is your first time you may want to read up on registration etc. but all you need is to find a domain that is available, buy it, and configure it as explained later.  Make sure you do not buy hosting with it, as some providers will try to bundle them together.  Well you can do whatever you want, but it's not necessary in this case.

2. Sign Up with AWS

Log on to aws.amazon.com and sign up for an account.  Choose your region, etc and keep going until you get to the main control panel.

3. Hold your horses!

The control panel may be overly complicated.  It isn't, though.  The number of services may be overwhelming, including the names, but we'll get through.  Only two services are required in our case.

Cloud providers typically offer more than just simple hosting.  Keep in mind that big enterprises are running their businesses here too, so this complexity is to be expected.  One of the core offerings of a cloud provider is storage.  Storage keeps everything in place - services need to save their logs, applications exist in storage, databases are persisted to storage...you get the pattern.  Again, due to the enterprisiness of this offering, the storage services have their own terminology.

Your usual "hard-disk" or "USB drive" (or floppy disk) is known as a bucket.  You have a bucket in the cloud in which you put your files.  Amazon offers storage in a service known as S3 - Simple Storage Service.  These bucket also tend to be dirt cheap.  A site a less than 10 pages and low to moderate traffic may cost you no more than €1 a month.

4. Creating the site

Now that you know about the basic concept, it is time to create the storage for your site.  In this example (and pretty much any other tutorial out there), we shall use the example.com domain.  Whenever you see this written down, replace it with the domain name you bought.  Do not prepend it with "www."; that is a subdomain, not the proper domain that you bought.

4.a. Sign in to https://console.aws.amazon.com/s3/;
4.b. Create a bucket named example.com;
4.c. Create another bucket www.example.com (with the www);
4.d. Upload your content to the first (example.com) bucket;

What we'll do is host the site on the example.com bucket and redirect any traffic coming in to www.example.com to it.

5. Prepare the site

Now you'll need to allow the public to access your buckets, otherwise they'll be forbidden from seeing your content (which, presumably, you want to be publicly accessible).  All you need is to attach the following bucket policy to your example.com bucket.  Again, make sure you replace example.com with your domain.

5.a. Set the policy
{
  "Version":"2012-10-17",
  "Statement":[{
"Sid":"AddPerm",
        "Effect":"Allow",
 "Principal": "*",
      "Action":["s3:GetObject"],
      "Resource":["arn:aws:s3:::example.com/*"
      ]
    }
  ]
}

5.b. Set up as static website by clicking on the bucket and select the Static Website Hosting section.  Choose the 'Enable' option;
5.c. Name the index page.  This is the "homepage" of your site.  Typically this is named "index.html" or similar;
5.d. Test the page by entering the Endpoint URL shown to you in your browser, just to make sure it is accessible;
5.e. Select the second bucket (www.example.com) and in the same section choose to redirect requests.  In the input field, enter your domain (without www.);

6. Wire it up

Another service that is required to properly route traffic to our site is Route 53.  As you've seen, you endpoint is appended with a much longer address belonging to amazon.  You wouldn't want to distribute that URL to your clients, after all you bought your own domain.

Route 53 is basically a DNS service - an internet directory for converting example.com to a number that the internet understands.  You do not need to do any of this works, except how to inform the registrar about your shining new website on AWS.  Here's how:

6.a. Open up https://console.aws.amazon.com/route53 and create a hosted zone for your domain (no www.) - Click Get Started Now under DNS Management, or just go to Hosted Zones and then Create Hosted Zone;
6.b. In the details section you'll see a Delegation Set - a list of addresses.  Write these down somewhere, we'll use them later on;
6.c. Click Create Record Set and enter you domain name.  Mark it as Alias and from the Alias target select your bucket.  Do this also for the www.example.com (point it to its own bucket).

7. Finishing

Now that everything is set up on AWS, all you need to do is inform the domain registrar (the site from where you bought your domain).  Remember the 4 addresses in the Delegation Set?  These will now be used to configure the DNS addresses for your domain.  What you need to do is log in to your domain registrar control panel and configure your domain.  Somewhere you should be able to change the DNS settings for it.  Not all providers have four fields - there may be more, there may be less.  Enter all four addresses in the delegation set in the domain configuration.  If there are less than four fields, that's it.  If there are more than four, leave the rest empty.

8.  Live!

Now that you're done, you may need to wait a few minutes until the DNS settings are updated.  This is not related to your site on AWS but on the nature of DNS - i.e. people's ability to enter example.com and be properly taken to your site.  These may take up to 48 hours, but in my case it was only a matter of minutes.

Hope you found this helpful!

20 December, 2011

Remote Desktop Viewer - The cheap way [Part 1]

Microsoft RDP, RemoteFX, VNC.  That is the real stuff.  Solutions such as those will allow you to secure your connections, log you in to your desktop, compress the connection, etc.  But have you ever thought if it is possible to implement something rudimentary, totally in Java.  Actually it is possible.  But it's nothing much, and what I'll be doing here is a very, very basic implementation of an idea.  Obviously one can go on and enhance it, but it's almost totally impossible to produce a real solution, since Java does not have direct access to the OS, so for example you cannot remotely log-in, as you would for example using ssh.  Well it might be possible, but it would be an overkill.

As I said, I will simply implement an idea, so even though I know we won't be building the next Remote Desktop protocol, it is still interesting.

First we shall lay out some basic requirements.  Basically we will build a server and a client.  The server shall receive a request, it will then grab a screen shot, and send it back.  Meanwhile the client will wait for the server to reply with the image, and will then draw it.  This will go on until we disconnect.

So create three packages first, com.jf.rd, com.jf.rd.client and com.jf.rd.server.  Obviously you can name them whatever you want, but ideally you should have xxx.xxx.client and .server.

We'll start off with the server.  That way we can define what we expect from the client and what we intend to send back.

Now, in the server package create the JRDServer class.


package com.jf.rd.server;




public class JRDServer
{
public static int PORT;

public static String USER;
public static String PASS;

/**
* Parameters:
* Port, User, Password
* @param args
*/
public static void main(String[] args)
{
if (args.length < 3)
{
System.out.println("Usage: JRDServer Port User Password");
System.exit(0);
}

PORT = Integer.parseInt(args[0]);
USER = args[1];
PASS = args[2];

System.out.println("JRD Server sdtarted.  Will listen for connections on " +
"port " + PORT);

JRDServer server = new JRDServer();

server.start();
}

private ConnectionListen listen;

public JRDServer()
{
this.listen = new ConnectionListen(this);
}

public void start()
{
System.out.println("Service Thread starting...");
listen.startServer();
Thread srv = new Thread(listen);
srv.start();
}

public void stop()
{
System.out.println("Service Thread stopping...");
listen.stopServer();
listen.destroy();
}
}


This class is basically an entry point to the server.  I expect some basic Java knowledge so I will describe this only briefly.  We start the server by passing 3 arguments; the port to which we will bind, a username and a password.  The port is the real necessity, and as yet the user and password will not be really used, and will be there so that one day we can implement some sort of security.

There are also the start and stop methods.  start will initialise a listener class which will be running on a separate thread.  That way we can serve our clients in a parallel fashion and also prevent any user from blocking us to the rest of the application in a manner which will stop us from stopping the server.

stop simple stops the listener class and releases its resources.

Next up is the listening class.  This class will loop while the server is running and every time a connection is requested, an other, separate thread is created and the client is served.


package com.jf.rd.server;


import java.io.IOException;
import java.net.ServerSocket;


public class ConnectionListen implements Runnable
{
private boolean running;
private ServerSocket serv;

public ConnectionListen(JRDServer server)
{
try
{
serv = new ServerSocket(JRDServer.PORT);
}
catch (IOException e) 
{
System.err.println("The ServerSocket could not be initialised.");
System.err.println("Reason : " + e);
}
}

public void startServer()
{
running = true;
}

public void stopServer()
{
running = false;
}

@Override
public void run()
{
while (running)
{
try
{
Connection conn = new Connection(serv.accept());
Thread tr = new Thread(conn);
tr.start();
}
catch (IOException e) 
{
System.err.println("A connection could not be accepted.");
System.err.println("Reason : " + e);
}
}
}

public void destroy()
{
try
{
serv.close();
}
catch (IOException e) 
{
System.err.println("The ServerSocket was not closed.");
System.err.println("Reason : " + e);
}
}
}


This time, a server socket is passed as a variable to the constructor. This is the socket which will listen for and accept connections.  The run method, which is the implementation of the Runnable class is what will be running on a separate thread.  Therefore we can simply put a while loop and, kind of, forget about it, since it won't be blocking us (the main thread).  It shall keep on looping until the running flag is false.  So when we start the server we must set running to true and then start it.  To stop it - well - set it to false, and the looping will stop.

Of course, if we won't be listening for any more connections, we should close the server socket.

Finally, the Connection class is created.  Once this is done, the server is basically complete.  Now I should explain what will happen when this is actually run.  Any client that shall connect to this server will receive a byte stream resulting from a screenshot.  It is irrelevant if the client is a web browser, a mobile app or a simple socket.  Also, we won't be checking what the client is actually requesting, so as you can see, the username and password are irrelevant.   That means that you should either practice, and implement an authentication system (easily done) or simply avoid running this server if you fear someone might connect to it and, sort of, spy on you (aye, this is easier).

So, to the connection class.

package com.jf.rd.server;


import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.Socket;


import javax.imageio.ImageIO;


public class Connection implements Runnable
{
private static final int IMG_WIDTH  = 960;
private static final int IMG_HEIGHT = 600;

private Socket connSock;
private static final int BUF_SIZE = 2048;
static final byte[] EOL =
{ (byte) '\r', (byte) '\n' };
private byte[] buf;


public Connection(Socket connSock)
{
this.connSock = connSock;
buf = new byte[BUF_SIZE];
}


@Override
public void run()
{
try
{
InputStream is = new BufferedInputStream(connSock.getInputStream());
PrintStream ps = new PrintStream(connSock.getOutputStream());


for (int i = 0; i < BUF_SIZE; i++)
buf[i] = 0;


int nread = 0, r = 0;


outerloop: while (nread < BUF_SIZE)
{
r = is.read(buf, nread, BUF_SIZE - nread);
if (r == -1) return;
int i = nread;
nread += r;
for (; i < nread; i++)
{
if (buf[i] == (byte) '\n' || buf[i] == (byte) '\r')
break outerloop;
}
}


System.out.println("Done reading.");


Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Rectangle screenRectangle = new Rectangle(screenSize);
Robot robot = new Robot();
BufferedImage image = robot.createScreenCapture(screenRectangle);
int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
image = resizeImage(image, type);

ImageIO.write(image, "JPG", connSock.getOutputStream());


ps.flush();


connSock.close();
}
catch (Exception e)
{
System.err.println("Error, somewhere...");
e.printStackTrace();
}
}


private static BufferedImage resizeImage(BufferedImage originalImage,
int type)
{
BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
g.dispose();
g.setComposite(AlphaComposite.Src);
 
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
 
return resizedImage;
}


}


There it is then.  The Main screen grabber and sender.  We're not doing much here;  just receiving a request and then write "Done reading" when the process finishes, and then a picture is sent.  The resizeImage method is used to reduce the size of the image so that we do not send an image the size of your screen resolution.  That would be slow and besides, you can also specify what "resolution" you intend to receive.  The socket is also closed here, that's important too.  The lines between printing "done reading" and ImageIO.write are grabbing the screen using the AWT (Advanced Window Toolkit), so what this means is that you must have an OS that supports GUI (i.e. not headless, as it is known) and you must be logged in basically, since it grabs the screen as seen by the current user.  Therefore apart from the fact that we cannot remotely login, we also can't turn off the video card.  You can turn off the screen, obviously (lol).

That was part one of this, erm, tutorial, or whatever it is.  I like doing these sort of mini programs when I am trying to solve other problems, that's why they are not at the bleeding edge of technology.  And then, when I'm done, I just write something about it, maybe someone out there learns something hehe.

The next thing we'll do, is build a client application.  I currently plan on supporting only viewing, but eventually, we might spice it up a bit by adding cursor support so that you may click on the client and it will then be forwarded to the server and eventually consumed by the OS that is hosting the server.

Also, the second part will probably come out either just before 2012, or probably in the first week of January, so until then, Merry Christmas and a Happy New Year! :D