1page.title=GCM HTTP Connection Server
2@jd:body
3
4<div id="qv-wrapper">
5<div id="qv">
6
7
8<h2>In this document</h2>
9
10<ol class="toc">
11  <li><a href="#auth">Authentication</a> </li>
12  <li><a href="#request">Request Format</a> </li>
13  <li><a href="#response">Response Format</a>
14  <ol class="toc">
15    <li><a href="#success">Interpreting a success response</a>
16    <li><a href="#error_codes">Interpreting an error response</a>
17    <li><a href="#example-responses">Example responses</a>
18  </ol>
19  </li>
20  <li><a href="#app-server">Implementing an HTTP-Based App Server</a>
21</ol>
22
23<h2>See Also</h2>
24
25<ol class="toc">
26<li><a href="server-ref.html">Server Reference</a></li>
27<li><a href="gs.html">Getting Started</a></li>
28<li><a href="client.html">Implementing GCM Client</a></li>
29<li><a href="ccs.html">Cloud Connection Server</a></li>
30
31
32</ol>
33
34</div>
35</div>
36
37<p>This document describes the Google Cloud Messaging (GCM) HTTP
38connection server. Connection servers
39are the Google-provided servers that take messages from the 3rd-party
40application server and sending them to the device.</p>
41
42<p class="note"><strong>Note:</strong> The content in this document
43applies to <a href="http://developer.chrome.com/apps/cloudMessaging">
44GCM with Chrome apps</a> as well as Android.</p>
45
46<p>See the
47<a href="server-ref.html">Server Reference</a> for a list of all the message
48parameters and which connection server(s) supports them.</p>
49
50
51<h2 id="auth">Authentication</h2>
52
53<p>To send a  message, the application server issues a POST request. For example:</p>
54<pre>https://android.googleapis.com/gcm/send</pre>
55<p>A  message request is made of 2 parts: HTTP header and HTTP body.</p>
56
57<p>The HTTP header must contain the following headers:</p>
58<ul>
59  <li><code>Authorization</code>: key=YOUR_API_KEY</li>
60  <li><code>Content-Type</code>: <code>application/json</code> for JSON;
61<code>application/x-www-form-urlencoded;charset=UTF-8</code> for plain text.
62If <code>Content-Type</code> is omitted, the format
63is assumed to be plain text.
64  </li>
65</ul>
66
67<p>For example:
68</p>
69
70<pre>Content-Type:application/json
71Authorization:key=AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA
72
73{
74  "registration_ids" : ["APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx..."],
75  "data" : {
76    ...
77  },
78}</pre>
79
80
81<p>The HTTP body content depends on whether you're using JSON or plain text.
82See
83<a href="server-ref.html#params">the Server Reference</a> for a list of all the
84parameters your JSON or plain text message can contain.</p>
85
86
87  <h2 id="request">Request Format</h2>
88
89<p>This section shows you how to format a request for both JSON and plain text. See
90the <a href="server-ref.html#table1">Server Reference</a> for a complete
91list of the fields you can include in a request.</p>
92
93  <p>Here is the smallest possible request (a message without any parameters and
94just one recipient) using JSON:</p>
95
96  <pre class="prettyprint pretty-json">{ &quot;registration_ids&quot;: [ &quot;42&quot; ] }</pre>
97
98  <p>And here the same example using plain text:</p>
99  <pre class="prettyprint">registration_id=42</pre>
100
101  <p> Here is a message with a payload and 6 recipients:</p>
102
103  <pre class="prettyprint pretty-HTML">{ "data": {
104    "score": "5x1",
105    "time": "15:10"
106  },
107  "registration_ids": ["4", "8", "15", "16", "23", "42"]
108}</pre>
109  <p>Here is a message with all optional fields set and 6 recipients:</p>
110  <pre class="prettyprint pretty-json">{ "collapse_key": "score_update",
111  "time_to_live": 108,
112  "delay_while_idle": true,
113  "data": {
114    "score": "4x8",
115    "time": "15:16.2342"
116  },
117  "registration_ids":["4", "8", "15", "16", "23", "42"]
118}</pre>
119  <p>And here is the same message using plain-text format (but just 1 recipient):  </p>
120
121  <pre class="prettyprint">collapse_key=score_update&amp;time_to_live=108&amp;delay_while_idle=1&amp;data.score=4x8&amp;data.time=15:16.2342&amp;registration_id=42
122  </pre>
123
124<p>Here is a message that includes a notification key and payload:</p>
125
126<pre>
127{
128  "data": {
129    "message": "ciao"
130  },
131  "notification_key":"aUniqueKey"
132}
133</pre>
134
135<p>For more information about notifications and how to use them, see
136<a href="{@docRoot}google/gcm/notifications.html">User Notifications</a>.</p>
137
138
139<p class="note"><strong>Note:</strong> If your organization has a firewall
140that restricts the traffic to or
141from the Internet, you need to configure it to allow connectivity with GCM in order for
142your GCM client apps to receive messages.
143The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but
144it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should allow
145your firewall to accept outgoing connections to all IP addresses
146contained in the IP blocks listed in Google's ASN of 15169.</p>
147
148
149
150<h2 id="response">Response format</h2>
151
152<p>There are two possible outcomes when trying to send a message:</p>
153<ul>
154  <li>The message is processed successfully. The HTTP response has a 200 status, and
155the body contains more information about the status of the message (including possible errors).</li>
156  <li>The GCM server rejects the request. The HTTP response contains a
157non-200 status code (such as 400, 401 or 5xx).</li>
158</ul>
159
160<h3 id="success">Interpreting a success response</h3>
161<p>When a JSON request is successful (HTTP status code 200), the response body
162contains a JSON object with the following fields:</p>
163<table>
164  <tr>
165    <th>Field</th>
166    <th>Description</th>
167  </tr>
168  <tr>
169    <td><code>multicast_id</code></td>
170    <td>Unique ID (number) identifying the multicast message.</td>
171  </tr>
172  <tr>
173    <td><code>success</code></td>
174    <td>Number of messages that were processed without an error.</td>
175  </tr>
176  <tr>
177    <td><code>failure</code></td>
178    <td>Number of messages that could not be processed.</td>
179  </tr>
180  <tr>
181    <td><code>canonical_ids</code></td>
182    <td>Number of results that contain a canonical registration ID. See
183<a href="adv.html#canonical">Advanced Topics</a> for more discussion of this topic.</td>
184  </tr>
185  <tr>
186    <td><code>results</code></td>
187    <td>Array of objects representing the status of the messages processed. The
188objects are listed in the same order as the request (i.e., for each registration
189ID in the request, its result is listed in the same index in the response) and
190they can have these fields:<br>
191      <ul>
192        <li><code>message_id</code>: String representing the message when it was
193successfully processed.</li>
194        <li><code>registration_id</code>: If set,  means that GCM processed the
195message but it has another canonical registration ID for that device, so sender
196should replace the IDs on future requests (otherwise they might be rejected).
197This field is never set if there is an error in the request.
198        </li>
199        <li><code>error</code>: String describing an error that occurred while
200processing the message for that recipient. The possible values are the same as
201documented in the above table, plus &quot;Unavailable&quot;  (meaning GCM servers
202were busy and could not process the message for that  particular recipient, so
203it could be retried).</li>
204    </ul></td>
205  </tr>
206</table>
207<p>If the value of <code>failure</code> and <code>canonical_ids</code> is 0, it's
208not necessary to parse the remainder of the response. Otherwise, we recommend
209that you iterate through the results field and do the following for each object
210in that list:</p>
211<ul>
212  <li>If <code>message_id</code> is set, check for <code>registration_id</code>:
213    <ul>
214      <li>If <code>registration_id</code> is set, replace the original ID with
215the new value (canonical ID) in your server database. Note that the original ID
216is not part of the result, so you need to obtain it from the list of
217code>registration_ids</code> passed in the request (using the same index).</li>
218    </ul>
219  </li>
220  <li>Otherwise, get the value of <code>error</code>:
221    <ul>
222      <li>If it is <code>Unavailable</code>, you could retry to send it in another
223request.</li>
224      <li>If it is <code>NotRegistered</code>, you should remove the registration
225ID from your server database because the application was uninstalled from the
226device, or the client app isn't configured to receive
227messages.</li>
228      <li>Otherwise, there is something wrong in the registration ID passed in
229the request; it is probably a non-recoverable error that will also require removing
230the registration from the server database. See <a href="#error_codes">Interpreting
231an error response</a> for all possible error values.</li>
232    </ul>
233  </li>
234</ul>
235
236<p>When a plain-text request is successful (HTTP status code 200), the response
237body contains 1 or 2 lines in the form of key/value pairs.
238The first line is always available and its content is either <code>id=<em>ID of
239sent message</em></code> or <code>Error=<em>GCM error code</em></code>. The second
240line, if available,
241has the format of <code>registration_id=<em>canonical ID</em></code>. The second
242line is optional, and it can only be sent if the first line is not an error. We
243recommend handling the plain-text response in a similar way as handling the
244JSON response:</p>
245<ul>
246  <li>If first line starts with <code>id</code>, check second line:
247    <ul>
248      <li>If second line starts with <code>registration_id</code>, gets its value
249and replace the registration IDs in your server database.</li>
250    </ul>
251  </li>
252  <li>Otherwise, get the value of <code>Error</code>:
253    <ul>
254      <li>If it is <code>NotRegistered</code>, remove the registration ID from
255your server database.</li>
256      <li>Otherwise, there is probably a non-recoverable error (<strong>Note:
257</strong>Plain-text requests will never return <code>Unavailable</code> as the
258error code, they would have returned a 500 HTTP status instead).</li>
259    </ul>
260  </li>
261</ul>
262
263<h3 id="error_codes">Interpreting an error response</h3>
264<p>Here are the recommendations for handling the different types of error that
265might occur when trying to send a message to a device:</p>
266
267<dl>
268<dt id="missing_reg"><strong>Missing Registration ID</strong></dt>
269<dd>Check that the request contains a registration ID (either in the
270<code>registration_id</code> parameter in a plain text message, or in the
271<code>registration_ids</code> field in JSON).
272<br/>Happens when error code is <code>MissingRegistration</code>.</dd>
273
274<dt id="invalid_reg"><strong>Invalid Registration ID</strong></dt>
275<dd>Check the formatting of the registration ID that you pass to the server. Make
276sure it matches the registration ID the client app receives and that you're
277not truncating it or adding additional characters.
278<br/>Happens when error code is <code>InvalidRegistration</code>.</dd>
279
280<dt id="mismatched_sender"><strong>Mismatched Sender</strong></dt>
281<dd>A registration ID is tied to a certain group of senders. When an application
282registers for GCM usage, it must specify which senders are allowed to send messages.
283Make sure you're using one of those when trying to send messages to the device.
284If you switch to a different sender, the existing registration IDs won't work.
285Happens when error code is <code>MismatchSenderId</code>.</dd>
286
287<dt id="unreg_device"><strong>Unregistered Device</strong></dt>
288<dd>An existing registration ID may cease to be valid in a number of scenarios, including:
289<ul>
290  <li>If the application manually unregisters.</li>
291  <li>If the application is automatically unregistered, which can happen
292(but is not guaranteed) if the user uninstalls the application.</li>
293  <li>If the registration ID expires. Google might decide to refresh registration
294IDs. </li>
295  <li>If the application is updated but the new version is not configured to receive
296messages.</li>
297</ul>
298For all these cases, you should remove this registration ID from the 3rd-party
299server and stop using it to send
300messages.
301<br/>Happens when error code is <code>NotRegistered</code>.</dd>
302
303<dt id="big_msg"><strong>Message Too Big</strong></dt>
304  <dd>The total size of the payload data that is included in a message can't
305exceed 4096 bytes. Note that this includes both the size of the keys as well
306as the values.
307<br/>Happens when error code is <code>MessageTooBig</code>.</dd>
308
309<dt id="invalid_datakey"><strong>Invalid Data Key</strong></dt>
310<dd>The payload data contains a key (such as <code>from</code> or any value
311prefixed by <code>google.</code>) that is used internally by GCM and therefore cannot be used.
312Note that some words (such as <code>collapse_key</code>) are also used by GCM
313but are allowed in the payload, in which case the payload value will be
314overridden by the GCM value.
315<br />
316Happens when the error code is <code>InvalidDataKey</code>.</dd>
317
318<dt id="ttl_error"><strong>Invalid Time To Live</strong></dt>
319  <dd>The value for the Time to Live field must be an integer representing
320a duration in seconds between 0 and 2,419,200 (4 weeks). Happens when error code
321is <code>InvalidTtl</code>.
322</dd>
323
324  <dt id="auth_error"><strong>Authentication Error</strong></dt>
325  <dd>The sender account that you're trying to use to send a message couldn't be
326authenticated. Possible causes are: <ul>
327<li>Authorization header missing or with invalid syntax.</li>
328<li>Invalid project number sent as key.</li>
329<li>Key valid but with GCM service disabled.</li>
330<li>Request originated from a server not whitelisted in the Server Key IPs.</li>
331
332</ul>
333When there is an Authentication Error, you can check the validity of your API key by running You can check the validity
334of your API key by running the following command (this example shows what you
335would do on Android; see the documentation for your platform):<br/>
336
337<pre># api_key=YOUR_API_KEY
338
339# curl --header "Authorization: key=$api_key" --header Content-Type:"application/json" https://android.googleapis.com/gcm/send  -d "{\"registration_ids\":[\"ABC\"]}"</pre>
340
341
342
343If you receive a 401 HTTP status code, your API key is not valid. Otherwise you
344should see something like this:<br/>
345
346<pre>
347{"multicast_id":6782339717028231855,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
348</pre>
349If you want to confirm the validity of a registration ID, you can do so by
350replacing "ABC" with the registration ID.
351<br/>
352Happens when the HTTP status code is 401.
353
354  <dt id="timeout"><strong>Timeout</strong></dt>
355
356<dd>The server couldn't process the request in time. You should retry the
357same request, but you MUST obey the following requirements:
358
359<ul>
360
361<li>Honor the <code>Retry-After</code> header if it's included in the response
362from the GCM server.</li>
363
364
365<li>Implement exponential back-off in your retry mechanism. This means an
366exponentially increasing delay after each failed retry (e.g. if you waited one
367second before the first retry, wait at least two second before the next one,
368then 4 seconds and so on). If you're sending multiple messages, delay each one
369independently by an additional random amount to avoid issuing a new request for
370all messages at the same time.</li>
371
372
373Senders that cause problems risk being blacklisted.
374<br />
375Happens when the HTTP status code is between 501 and 599, or when the
376<code>error</code> field of a JSON object in the results array is <code>Unavailable</code>.
377</dd>
378
379<dt id="internal_error"><strong>Internal Server Error</strong></dt>
380
381<dd>
382The server encountered an error while trying to process the request. You
383could retry the same request (obeying the requirements listed in the <a href="#timeout">Timeout</a>
384section), but if the error persists, please report the problem to Google.
385<br />
386Happens when the HTTP status code is 500, or when the <code>error</code> field of a JSON
387object in the results array is <code>InternalServerError</code>.
388</dd>
389
390<dt id="restricted_package_name"><strong>Invalid Package Name</strong></dt>
391
392<dd>
393A message was addressed to a registration ID whose package name did not match
394the value passed in the request. Happens when error code is
395<code>InvalidPackageName</code>.
396</dd>
397
398<dt id="big_msg"><strong>Device Message Rate Exceeded</strong></dt>
399  <dd>The rate of messages to a particular device is too high. You should reduce the number
400of messages sent to this device and should not retry sending to this device immediately.
401<br/>Happens when error code is <code>DeviceMessageRateExceeded</code>.</dd>
402
403</dl>
404
405<h3 id="example-responses">Example responses</h3>
406<p>This section shows a few examples of responses indicating messages that were
407processed successfully. See <a href="#request">Request Format</a> for
408the requests these responses are based on.</p>
409<p> Here is a simple case of a JSON message successfully sent to one recipient
410without canonical IDs in the response:</p>
411<pre class="prettyprint pretty-json">{ "multicast_id": 108,
412  "success": 1,
413  "failure": 0,
414  "canonical_ids": 0,
415  "results": [
416    { "message_id": "1:08" }
417  ]
418}</pre>
419
420<p>Or if the request was in plain-text format:</p>
421<pre class="prettyprint">id=1:08
422</pre>
423
424<p>Here are JSON results for 6 recipients (IDs 4, 8, 15, 16, 23, and 42 respectively)
425with 3 messages successfully processed, 1 canonical registration ID returned,
426and 3 errors:</p>
427<pre class="prettyprint pretty-json">{ "multicast_id": 216,
428  "success": 3,
429  "failure": 3,
430  "canonical_ids": 1,
431  "results": [
432    { "message_id": "1:0408" },
433    { "error": "Unavailable" },
434    { "error": "InvalidRegistration" },
435    { "message_id": "1:1516" },
436    { "message_id": "1:2342", "registration_id": "32" },
437    { "error": "NotRegistered"}
438  ]
439}
440</pre>
441<p> In this example:</p>
442<ul>
443  <li>First message: success, not required.</li>
444  <li>Second message: should be resent (to registration ID 8).</li>
445  <li>Third message: had an unrecoverable error (maybe the value got corrupted
446in the database).</li>
447  <li>Fourth message: success, nothing required.</li>
448  <li>Fifth message: success, but the registration ID should be updated in the
449server database (from 23 to 32).</li>
450  <li>Sixth message: registration ID (42) should be removed from the server database
451because the application was uninstalled from the device.</li>
452</ul>
453<p>Or if just the 4th message above was sent using plain-text format:</p>
454<pre class="prettyprint">Error=InvalidRegistration
455</pre>
456<p>If the 5th message above was also sent using plain-text format:</p>
457<pre class="prettyprint">id=1:2342
458registration_id=32
459</pre>
460
461
462<h2 id="app-server">Implementing an HTTP-Based App Server</h2>
463
464<p>This section gives examples of implementing an app server that works with the
465GCM HTTP connection server. Note that a full GCM implementation requires a
466client-side implementation, in addition to the server. This example is based on Android.</a>
467
468
469<p>Requirements</p>
470<p>For the web server:</p>
471<ul>
472  <li> <a href="http://ant.apache.org/">Ant 1.8</a> (it might work with earlier versions, but it's not guaranteed).</li>
473  <li>One of the following:
474    <ul>
475      <li>A running web server compatible with Servlets API version 2.5, such as
476<a href="http://tomcat.apache.org/">Tomcat 6</a> or <a href="http://jetty.codehaus.org/">Jetty</a>, or</li>
477      <li><a href="http://code.google.com/appengine/">Java App Engine SDK</a>
478version 1.6 or later.</li>
479    </ul>
480  </li>
481  <li>A Google account registered to use GCM.</li>
482  <li>The API  key for that account.</li>
483</ul>
484<p>For the Android application:</p>
485<ul>
486  <li>Emulator (or device) running Android 2.2 (ideally, 2.3 or above) with Google APIs.</li>
487  <li>The Google API project number of the account registered to use GCM.</li>
488</ul>
489
490<h3 id="gcm-setup">Setting Up GCM</h3>
491<p>Before proceeding with the server and client setup, it's necessary to register
492a Google account with the Google API Console, enable Google Cloud Messaging in GCM,
493and obtain an API key from the <a href="https://code.google.com/apis/console">
494Google API Console</a>.</p>
495<p>For instructions on how to set up GCM, see <a href="gs.html">Getting Started</a>.</p>
496
497
498<h3 id="server-setup">Setting Up an HTTP Server</h3>
499<p>This section describes the different options for setting up an HTTP server.</p>
500
501<h4 id="webserver-setup">Using a standard web server</h4>
502<p>To set up the server using a standard, servlet-compliant web server:</p>
503<ol>
504  <li>From the <a href="http://code.google.com/p/gcm">open source site</a>,
505download the following directories: <code>gcm-server</code>,
506<code>samples/gcm-demo-server</code>, and <code>samples/gcm-demo-appengine</code>.</p>
507
508
509  <li>In a text editor, edit the <code>samples/gcm-demo-server/WebContent/WEB-INF/classes/api.key</code> and replace the existing text with the API key obtained above.</li>
510  <li>In a shell window, go to the <code>samples/gcm-demo-server</code> directory.</li>
511  <li>Generate the server's WAR file by running <code>ant war</code>:</li>
512
513  <pre class="prettyprint">$ ant war
514
515Buildfile:build.xml
516
517init:
518   [mkdir] Created dir: build/classes
519   [mkdir] Created dir: dist
520
521compile:
522   [javac] Compiling 6 source files to build/classes
523
524war:
525     [war] Building war: <strong>dist/gcm-demo.war</strong>
526
527BUILD SUCCESSFUL
528Total time: 0 seconds
529</pre>
530
531  <li>Deploy the <code>dist/gcm-demo.war</code> to your running server. For instance, if you're using Jetty, copy <code>gcm-demo.war</code> to the <code>webapps</code> directory of the Jetty installation.</li>
532  <li>Open the server's main page in a browser. The URL depends on the server you're using and your machine's IP address, but it will be something like <code>http://192.168.1.10:8080/gcm-demo/home</code>, where <code>gcm-demo</code> is the application context and <code>/home</code> is the path of the main servlet.
533
534  </li>
535</ol>
536<p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code> on Linux or MacOS, or <code>ipconfig</code> on Windows. </p>
537
538<p> You server is now ready.</p>
539
540<h4 id="appengine-setup">Using App Engine for Java</h4>
541
542<p>To set up the server using a standard App Engine for Java:</p>
543<ol>
544  <li>Get the files from the <a href="http://code.google.com/p/gcm">open source
545site</a>, as described above.</p>
546  </li>
547  <li>In a text editor, edit
548<code>samples/gcm-demo-appengine/src/com/google/android/gcm/demo/server/ApiKeyInitializer.java</code>
549and replace the existing text with the API key obtained above.
550
551  <p class="note"><strong>Note:</strong> The API key value set in that class will
552be used just once to create a persistent entity on App Engine. If you deploy
553the application, you can use App Engine's <code>Datastore Viewer</code> to change
554it later.</p>
555
556  </li>
557  <li>In a shell window, go to the <code>samples/gcm-demo-appengine</code> directory.</li>
558  <li>Start the development App Engine server by <code>ant runserver</code>,
559using the <code>-Dsdk.dir</code> to indicate the location of the App Engine SDK
560and <code>-Dserver.host</code> to set your server's hostname or IP address:</li>
561
562<pre class="prettyprint">
563$ ant -Dsdk.dir=/opt/google/appengine-java-sdk runserver -Dserver.host=192.168.1.10
564Buildfile: gcm-demo-appengine/build.xml
565
566init:
567    [mkdir] Created dir: gcm-demo-appengine/dist
568
569copyjars:
570
571compile:
572
573datanucleusenhance:
574  [enhance] DataNucleus Enhancer (version 1.1.4) : Enhancement of classes
575  [enhance] DataNucleus Enhancer completed with success for 0 classes. Timings : input=28 ms, enhance=0 ms, total=28 ms. Consult the log for full details
576  [enhance] DataNucleus Enhancer completed and no classes were enhanced. Consult the log for full details
577
578runserver:
579     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.jetty.JettyLogger info
580     [java] INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger
581     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml
582     [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/appengine-web.xml
583     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml
584     [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/web.xml
585     [java] Jun 15, 2012 8:46:09 PM com.google.android.gcm.demo.server.ApiKeyInitializer contextInitialized
586     [java] SEVERE: Created fake key. Please go to App Engine admin console, change its value to your API Key (the entity type is 'Settings' and its field to be changed is 'ApiKey'), then restart the server!
587     [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
588     [java] INFO: The server is running at http://192.168.1.10:8080/
589     [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
590     [java] INFO: The admin console is running at http://192.168.1.10:8080/_ah/admin
591</pre>
592
593  <li>Open the server's main page in a browser. The URL depends on the server
594you're using and your machine's IP address, but it will be something like
595<code>http://192.168.1.10:8080/home</code>, where <code>/home</code>
596is the path of the main servlet.</li>
597
598  <p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code>
599on Linux or MacOS, or <code>ipconfig</code> on Windows.</p>
600
601</ol>
602<p> You server is now ready.</p>
603