Tips & Tricks of Using 1&1 Shared Hosting Environment

by Gong Liu March 08, 2009 06:33

I use 1&1 (1and1.com) shared hosting for this blog site and some of my other projects because of its reasonally good set of features and ridiculously low price. You can get a business account with 250GB web space and 2500GB monthly transfer volume for only 10 bucks a month. However, a shared web hosting environment such as 1&1 has some limitations that a real web administrator may not get used to at first. As our company's sr. developer/ administrator, I have full control over some 30 web servers, application servers and database servers via remote desktop. I have full administrator rights. I can run any applications I want on these servers. But with my shared hosting account at 1&1, I can't even access the IIS admin console or the SQL Server 2005 Management Studio. On the development side, the limitations include: you can't configure all the web application features via your web.config file; you can't connect to other web servers/sites from your code without going through a proxy server.

In the following sections I'll share with you some tips and tricks I found out through numerous emails and phone calls to the sometimes not-so-helpful 1&1 technical support. Note that the tips and tricks are based on 1&1 MS Shared Hosting package (Windows Server 2003, IIS 6.0, SQL Server 2005, and .Net Framework 2.0). However, the general ideas may be applicable to similar hosting environment offered by other hosting companies.

Sending Emails from a Web Application

First of all, you CAN NOT configure the mail server in your web.config file like so:

    <system.net>
        <mailSettings>
            <smtp from="admin@mydomain.com">
                <network host="smtp.1and1.com" password="mypassword" userName="myusername" />
            </smtp>
        </mailSettings>
    </system.net>

This configureation section will simply be ignored by the shared server.      

Secondly, the mail server "smtp.1and1.com" does not need a userName/password. It doesn't mean the mail server is open to public, though. You have to be an 1&1 customer and you can only send out emails from your application running on one of the 1&1 web servers. You can not use the mail server from your application running on your development machine at your home, for example.

If you want to, you can define the mail server host and the sender email address in the appSettings section of your web.config file, such as:

  <appSettings>
    <add key="SmtpHost" value="smtp.1and1.com" />
    <add key="Sender" value="admin@mydomain.com" />
  </appSettings> 

Here is the sample code in C# for sending an email using the above configuration:

    try
    {
        MailMessage mm = new MailMessage();
        mm.From = new MailAddress(ConfigurationManager.AppSettings["Sender"]);
        mm.To.Add(yourname@somedomain.com);
        mm.Subject = "Test from 1&1 Mail Server";
        mm.IsBodyHtml = false;
        mm.Body = "This is a test email.";
        SmtpClient smtp = new SmtpClient();
        smtp.Host = ConfigurationManager.AppSettings["SmtpHost"];
        smtp.Send(mm);
    }
    catch (Exception ex)
    {
        //handle the exception here
    } 

Communicating with PayPal Server via a Proxy Server

For security reasons your web application on a shared web server can not contact an outside server directly. It has to go through a proxy server. For example, if you design a website that accepts donations via Paypal and you want PayPal to instantly notify your application the status of a transaction (Instant Payment Notification, or IPN), then your application needs to communicate with PayPal server via a proxy server, as shown in the following diagram.

   paypal flow

The flow of communications among a client and the servers involved is as follow:

  1. The client requests a donation page from the web server that is running your website/application.
  2. The web server returns such a page, which includes a web form with at least a textbox for donation amount and a submit button.
  3. The client enters the amount to donate and clicks the submit button to submit the form to the PayPal server for payment processing.
  4. There are a couple of round trips between the client and the PayPal server for such activities as logging in the client's PayPal account, verifying payment info, and acknolodging the payment.
  5. At the end of the series of activities in (4) is a page that allows the client to return to your website either automatically or by pressing a return button.
  6. The client returns from PayPal website to a thank-you page on your website. The url of the thank-you page is specified in the donation page in (2) or pre-configured in your PayPal account. At this point, the actual transaction - transferring money from the client's PayPal account to your PayPal account - may or my not have happened yet. All you care about is that whenever it happens your application should know so that it can take appropriate actions.
  7. When the transaction does happen, the PayPal server sends the transaction detail to your application on the web server by requesting an IPN page. The url of the IPN page is specified in the donation page in (2) or pre-configured in your PayPal account.
  8. Your application responses the request with the transaction detail received in (7), plus a notification validation flag (_notify-validate). This is the step where you use the proxy server to send message back to the PayPal server.
  9. The PayPal server verifies the message and sends back the validation status. If the status is VERIFIED, you may want to update a database with the transaction detail and/or email a receipt to the client. If the status indicates some kind of error, you may want to log the error for further analysis.

The C# code for the IPN page looks like this:

    protected void Page_Load(object sender, EventArgs e)
    {
        //Parse transaction detail from Paypal 
        byte[] param = Request.BinaryRead(Request.ContentLength);
        string strRequest = Encoding.ASCII.GetString(param);
        Dictionary<string, string> nvs = new Dictionary<string, string>();
        string[] items = strRequest.Split("&".ToCharArray());
        foreach (string item in items)
        {
            string[] parts = item.Split("=".ToCharArray());
            nvs.Add(parts[0], HttpUtility.UrlDecode(parts[1]));
        }        

        //Post back to either sandbox or live
        //string url = "https://www.sandbox.paypal.com/cgi-bin/webscr";
        string url = https://www.paypal.com/cgi-bin/webscr; 
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
        req.Method = "POST";
        req.ContentType = "application/x-www-form-urlencoded";

        //Append validation flag to the orginal transaction detail
        strRequest += "&cmd=_notify-validate";
        req.ContentLength = strRequest.Length;

        //Hook up 1&1 proxy server
        WebProxy proxy = new WebProxy(new Uri("http://ntproxy.1and1.com:3128"));
        req.Proxy = proxy;

        //Send transaction detail with the flag back to PayPal
        StreamWriter streamOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII);
        streamOut.Write(strRequest);
        streamOut.Close();

        //Get validation status from PayPal
        StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream());
        string strResponse = streamIn.ReadToEnd();
        streamIn.Close();

        //Send mail to payer or admin depending on validation status
        MailMessage mm = new MailMessage();
        mm.From = new MailAddress(ConfigurationManager.AppSettings["Sender"]);
        mm.IsBodyHtml = false;
        SmtpClient smtp = new SmtpClient();
        smtp.Host = ConfigurationManager.AppSettings["SmtpHost"];
        if (strResponse == "VERIFIED")
        {
            if (nvs["payment_status"] == "Completed")
            {
                mm.To.Add(nvs["payer_email"]);
                mm.Bcc.Add(ConfigurationManager.AppSettings["Sender"]);
                mm.Subject = string.Format("Thank you for you donation #{0}", nvs["txn_id"]);
                string body = string.Format("Dear {0},\n\nThank you for you donation of {1}{2}, paid on {3}. Transaction #: {4}\n\nSincerely,\n{5}", nvs["first_name"], nvs["mc_currency"], nvs["mc_gross"], nvs["payment_date"], nvs["txn_id"], ConfigurationManager.AppSettings["Sender"]);
                mm.Body = body;
                smtp.Send(mm);
            }
            else
            {
                mm.To.Add(ConfigurationManager.AppSettings["Sender"]);
                mm.Subject = "Incompleted transaction";
                mm.Body = strRequest;
                smtp.Send(mm);
            }
        }
        else if (strResponse == "INVALID")
        {
            mm.To.Add(ConfigurationManager.AppSettings["Sender"]);
            mm.Subject = "Invalid transaction";
            mm.Body = strRequest;
            smtp.Send(mm);
        }
        else
        {
            mm.To.Add(ConfigurationManager.AppSettings["Sender"]);
            mm.Subject = "Bad transaction";
            mm.Body = strRequest;
            smtp.Send(mm);
        }
    } 

The above code is adapted from this PayPal code sample. Here are some key points to note about the code. First, we use a generic Dictionary to store the transaction detail from PayPal in name-value pairs. Doing so makes it a lot easier to retrieve any value by transaction item name in the later part of the code. Second, to make sure if the transaction data is indeed from PayPal, we need to send it to PayPal for validation. To contact PayPal server from 1&1 server, we need to go through 1&1 proxy server. This is done by creating a WebProxy object with 1&1 proxy server's url (http://ntproxy.1and1.com) and port number (3128), and assigning it to the Proxy property of the HttpWebRequest object. Finally, based on the validation status from Paypal we need to take some actions. For this sample code, we just email a receipt to the client (donor) if the transaction is valid. Or we send the site admin an email if the transaction is invalid or some error has happened.

To see a live demo click here. Don't forget to donate some money if you find this post is useful Wink 

One Account, Multiple Sites

1&1 business account allows you to configure up to 5 ASP.Net applications in separate folders under the account's root folder. Each application can have its own web.config, Global.asax files and everything. If you have multiple domain names, you can associate one for each application so it looks like separate websites. By default all you domain names point to your account root folder. 1&1 has a feature called domain destination. With domain destination supposedly you could point a domain to an application folder and when you type the domain name in a browser, it should go straight to application's default page. But, somehow, this feature does not seem to work. A workaround is to place a default page in your account root folder and the default page redirect requests to different application folders based on their http host names. This configuration is essentially equivalent to one parent application with up to 5 child applications.

In the following example, I assume you have 3 web applications, app1, app2 and app3, each in its own folder, and 3 corresponding domain names, mysite1.com, mysite2.com and mysite3.com. First, you need to specify app1, app2 and app3 are application folders. Here are the steps to do this:

  1. Launch Webfiles utility
  2. Select File -> Application Settings menu item
  3. Click Create button
  4. Select app1 folder, and click OK button
  5. Repeat steps 3 & 4 for other application folders.

Next, deploy app1, app2 and app3 to corresponding app folders. 

Create the following default.aspx page:

<%@ Page Language="C#" %>
<%
    string host = Request.ServerVariables["HTTP_HOST"];
    if (host.ToLower().IndexOf("mysite1.com") >= 0)
        Response.Redirect("app1/");
    else if (host.ToLower().IndexOf("mysite2.com") >= 0)
        Response.Redirect("app2/");
    else if (host.ToLower().IndexOf("mysite3.com") >= 0)
        Response.Redirect("app3/");
    else
        Response.Write("Under construction");  //your all other domains
%>

Finally, upload the page to your account root folder. Now, if you type http://www.mysite1.com in a browser, you will get to http://www.mysite1.com/app1/default.aspx. Similarly, if you type in http://www.mysite2.com, you will get to http://www.mysite2.com/app2/default.aspx, etc. Of course, nothing prevents a user from typing in http://www.mysite2.com/app1/default.aspx to get to the app1's default page with the domain mysite2.com, if he knows all your domains and folder structures. 

Here are some extra notes: 

  • You can add a web.config file to your account root folder, and in this case all you child applications will inherite the configuration.
  • If you have an 1&1 dedicated SSL certificate for one of your domains, you can not shared it with your other domains, because the certificate is issued for a fixed domain name. If you try to use the SSL certificate with other domain, you will get the error "There is a problem with this website's security certificate."  
  • If you want to, you can use a default.asp page in place of the default.aspx page. Here is what the default.asp page looks like:

<%
    Dim host
    host = Request.ServerVariables("HTTP_HOST")
    if InStr(LCase(host), "mysite1.com") > 0 then
        Response.Redirect("app1/")
    elseif InStr(LCase(host), "mysite2.com") > 0 then
        Response.Redirect("app2/")
    elseif InStr(LCase(host), "mysite3.com") > 0 then
        Response.Redirect("app3/")
    else
        Response.Write("Under construction")
    end if
%>

About

A seasoned computer professional. A tofu culture evangelist...
more >>

Tag Cloud

Calendar

<<  April 2017  >>
MoTuWeThFrSaSu
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

View posts in large calendar
Copyright © 2008-2011 Gong Liu. All rights reserved. | credits | contact me
The content on this site represents my own personal opinions, and does not reflect those of my employer in any way.