diff --git a/cmd/web.go b/cmd/web.go
index 4c4dbe94e9..1ce5acc783 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -226,7 +226,8 @@ func runWeb(ctx *cli.Context) error {
 	m.Group("/user/settings", func() {
 		m.Get("", user.Settings)
 		m.Post("", bindIgnErr(auth.UpdateProfileForm{}), user.SettingsPost)
-		m.Post("/avatar", binding.MultipartForm(auth.UploadAvatarForm{}), user.SettingsAvatar)
+		m.Combo("/avatar").Get(user.SettingsAvatar).
+			Post(binding.MultipartForm(auth.AvatarForm{}), user.SettingsAvatarPost)
 		m.Post("/avatar/delete", user.SettingsDeleteAvatar)
 		m.Combo("/email").Get(user.SettingsEmails).
 			Post(bindIgnErr(auth.AddEmailForm{}), user.SettingsEmailPost)
@@ -375,7 +376,7 @@ func runWeb(ctx *cli.Context) error {
 			m.Group("/settings", func() {
 				m.Combo("").Get(org.Settings).
 					Post(bindIgnErr(auth.UpdateOrgSettingForm{}), org.SettingsPost)
-				m.Post("/avatar", binding.MultipartForm(auth.UploadAvatarForm{}), org.SettingsAvatar)
+				m.Post("/avatar", binding.MultipartForm(auth.AvatarForm{}), org.SettingsAvatar)
 				m.Post("/avatar/delete", org.SettingsDeleteAvatar)
 
 				m.Group("/hooks", func() {
diff --git a/conf/app.ini b/conf/app.ini
index 3c36195ff6..e46436e65d 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -230,6 +230,9 @@ AVATAR_UPLOAD_PATH = data/avatars
 ; or a custom avatar source, like: http://cn.gravatar.com/avatar/
 GRAVATAR_SOURCE = gravatar
 DISABLE_GRAVATAR = false
+; Federated avatar lookup uses DNS to discover avatar associated
+; with emails, see http://www.libravatar.org
+ENABLE_FEDERATED_AVATAR = false
 
 [attachment]
 ; Whether attachments are enabled. Defaults to `true`
diff --git a/conf/locale/locale_en-US.ini b/conf/locale/locale_en-US.ini
index dd3d54d6f8..99b5d17363 100644
--- a/conf/locale/locale_en-US.ini
+++ b/conf/locale/locale_en-US.ini
@@ -96,6 +96,7 @@ offline_mode = Enable Offline Mode
 offline_mode_popup = Disable CDN even in production mode, all resource files will be served locally.
 disable_gravatar = Disable Gravatar Service
 disable_gravatar_popup = Disable Gravatar and custom sources, all avatars are uploaded by users or default.
+federated_avatar_lookup = Enable Federated Avatars Lookup
 disable_registration = Disable Self-registration
 disable_registration_popup = Disable user self-registration, only admin can create accounts.
 enable_captcha = Enable Captcha
@@ -239,6 +240,7 @@ form.name_pattern_not_allowed = Username pattern '%s' is not allowed.
 [settings]
 profile = Profile
 password = Password
+avatar = Avatar
 ssh_keys = SSH Keys
 social = Social Accounts
 applications = Applications
@@ -259,7 +261,9 @@ change_username_prompt = This change will affect the way how links relate to you
 continue = Continue
 cancel = Cancel
 
-enable_custom_avatar = Enable Custom Avatar
+lookup_avatar_by_mail = Lookup Avatar by mail
+federated_avatar_lookup = Federated Avatar Lookup
+enable_custom_avatar = Use Custom Avatar
 choose_new_avatar = Choose new avatar
 update_avatar = Update Avatar Setting
 delete_current_avatar = Delete Current Avatar
@@ -1044,6 +1048,7 @@ config.cookie_life_time = Cookie Life Time
 config.picture_config = Picture Configuration
 config.picture_service = Picture Service
 config.disable_gravatar = Disable Gravatar
+config.enable_federated_avatar = Enable Federated Avatars
 config.log_config = Log Configuration
 config.log_mode = Log Mode
 
diff --git a/models/user.go b/models/user.go
index 941dc054aa..d08b1cc8fa 100644
--- a/models/user.go
+++ b/models/user.go
@@ -254,7 +254,7 @@ func (u *User) RelAvatarLink() string {
 
 		return setting.AppSubUrl + "/avatars/" + com.ToStr(u.ID)
 	}
-	return setting.GravatarSource + u.Avatar
+	return base.AvatarLink(u.AvatarEmail)
 }
 
 // AvatarLink returns user avatar absolute link.
diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go
index 57451d9eb6..7bd6c7b9bc 100644
--- a/modules/auth/user_form.go
+++ b/modules/auth/user_form.go
@@ -36,11 +36,12 @@ type InstallForm struct {
 	RegisterConfirm bool
 	MailNotify      bool
 
-	OfflineMode         bool
-	DisableGravatar     bool
-	DisableRegistration bool
-	EnableCaptcha       bool
-	RequireSignInView   bool
+	OfflineMode           bool
+	DisableGravatar       bool
+	EnableFederatedAvatar bool
+	DisableRegistration   bool
+	EnableCaptcha         bool
+	RequireSignInView     bool
 
 	AdminName          string `binding:"OmitEmpty;AlphaDashDot;MaxSize(30)" locale:"install.admin_name"`
 	AdminPasswd        string `binding:"OmitEmpty;MaxSize(255)" locale:"install.admin_password"`
@@ -93,19 +94,25 @@ type UpdateProfileForm struct {
 	Email    string `binding:"Required;Email;MaxSize(254)"`
 	Website  string `binding:"Url;MaxSize(100)"`
 	Location string `binding:"MaxSize(50)"`
-	Gravatar string `binding:"OmitEmpty;Email;MaxSize(254)"`
 }
 
 func (f *UpdateProfileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
 	return validate(errs, ctx.Data, f, ctx.Locale)
 }
 
-type UploadAvatarForm struct {
-	Enable bool
-	Avatar *multipart.FileHeader
+const (
+	AVATAR_LOCAL  string = "local"
+	AVATAR_BYMAIL string = "bymail"
+)
+
+type AvatarForm struct {
+	Source      string
+	Avatar      *multipart.FileHeader
+	Gravatar    string `binding:"OmitEmpty;Email;MaxSize(254)"`
+	Federavatar bool
 }
 
-func (f *UploadAvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
+func (f *AvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
 	return validate(errs, ctx.Data, f, ctx.Locale)
 }
 
diff --git a/modules/base/tool.go b/modules/base/tool.go
index f045cb2270..b5125cab8a 100644
--- a/modules/base/tool.go
+++ b/modules/base/tool.go
@@ -205,12 +205,26 @@ func HashEmail(email string) string {
 }
 
 // AvatarLink returns avatar link by given email.
-func AvatarLink(email string) string {
-	if setting.DisableGravatar || setting.OfflineMode {
-		return setting.AppSubUrl + "/img/avatar_default.png"
+func AvatarLink(email string) (url string) {
+
+	if !setting.OfflineMode {
+		if setting.EnableFederatedAvatar && setting.LibravatarService != nil {
+			var err error
+			url, err = setting.LibravatarService.FromEmail(email)
+			if err != nil {
+				log.Error(1, "LibravatarService.FromEmail:: %v", err)
+			}
+		}
+		if len(url) == 0 && !setting.DisableGravatar {
+			url = setting.GravatarSource + HashEmail(email)
+		}
 	}
 
-	return setting.GravatarSource + HashEmail(email)
+	if len(url) == 0 {
+		url = setting.AppSubUrl + "/img/avatar_default.png"
+	}
+
+	return url
 }
 
 // Seconds-based time units
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index f59aa0884d..b8e8f65ef1 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -21,6 +21,7 @@ import (
 	"github.com/go-macaron/session"
 	_ "github.com/go-macaron/session/redis"
 	"gopkg.in/ini.v1"
+	"github.com/strk/go-libravatar"
 
 	"github.com/gogits/gogs/modules/bindata"
 	"github.com/gogits/gogs/modules/log"
@@ -140,9 +141,11 @@ var (
 	}
 
 	// Picture settings
-	AvatarUploadPath string
-	GravatarSource   string
-	DisableGravatar  bool
+	AvatarUploadPath  string
+	GravatarSource    string
+	DisableGravatar   bool
+	EnableFederatedAvatar   bool
+	LibravatarService *libravatar.Libravatar
 
 	// Log settings
 	LogRootPath string
@@ -462,8 +465,24 @@ func NewContext() {
 		GravatarSource = source
 	}
 	DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
+	EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool()
 	if OfflineMode {
 		DisableGravatar = true
+		EnableFederatedAvatar = false
+	}
+
+	if !DisableGravatar && EnableFederatedAvatar {
+		LibravatarService = libravatar.New()
+		parts := strings.Split(GravatarSource, "/")
+		if len(parts) >= 3 {
+			if parts[0] == "https:" {
+				LibravatarService.SetUseHTTPS(true)
+				LibravatarService.SetSecureFallbackHost(parts[2])
+			} else {
+				LibravatarService.SetUseHTTPS(false)
+				LibravatarService.SetFallbackHost(parts[2])
+			}
+		}
 	}
 
 	if err = Cfg.Section("ui").MapTo(&UI); err != nil {
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index bc850b638e..b8eb6743d7 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -222,6 +222,7 @@ func Config(ctx *context.Context) {
 	ctx.Data["SessionConfig"] = setting.SessionConfig
 
 	ctx.Data["DisableGravatar"] = setting.DisableGravatar
+	ctx.Data["EnableFederatedAvatar"] = setting.EnableFederatedAvatar
 
 	type logger struct {
 		Mode, Config string
diff --git a/routers/install.go b/routers/install.go
index 0af1f446c0..8b96ff8254 100644
--- a/routers/install.go
+++ b/routers/install.go
@@ -169,6 +169,7 @@ func Install(ctx *context.Context) {
 	// Server and other services settings
 	form.OfflineMode = setting.OfflineMode
 	form.DisableGravatar = setting.DisableGravatar
+	form.EnableFederatedAvatar = setting.EnableFederatedAvatar
 	form.DisableRegistration = setting.Service.DisableRegistration
 	form.EnableCaptcha = setting.Service.EnableCaptcha
 	form.RequireSignInView = setting.Service.RequireSignInView
@@ -329,6 +330,7 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
 
 	cfg.Section("server").Key("OFFLINE_MODE").SetValue(com.ToStr(form.OfflineMode))
 	cfg.Section("picture").Key("DISABLE_GRAVATAR").SetValue(com.ToStr(form.DisableGravatar))
+	cfg.Section("picture").Key("ENABLE_FEDERATED_AVATAR").SetValue(com.ToStr(form.EnableFederatedAvatar))
 	cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(com.ToStr(form.DisableRegistration))
 	cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(com.ToStr(form.EnableCaptcha))
 	cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(com.ToStr(form.RequireSignInView))
diff --git a/routers/org/setting.go b/routers/org/setting.go
index 128fba36a8..14681e4c59 100644
--- a/routers/org/setting.go
+++ b/routers/org/setting.go
@@ -83,8 +83,8 @@ func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
 	ctx.Redirect(ctx.Org.OrgLink + "/settings")
 }
 
-func SettingsAvatar(ctx *context.Context, form auth.UploadAvatarForm) {
-	form.Enable = true
+func SettingsAvatar(ctx *context.Context, form auth.AvatarForm) {
+	form.Source = auth.AVATAR_LOCAL
 	if err := user.UpdateAvatarSetting(ctx, form, ctx.Org.Organization); err != nil {
 		ctx.Flash.Error(err.Error())
 	} else {
diff --git a/routers/user/setting.go b/routers/user/setting.go
index 7412ce34d1..c5441f3543 100644
--- a/routers/user/setting.go
+++ b/routers/user/setting.go
@@ -22,6 +22,7 @@ import (
 
 const (
 	SETTINGS_PROFILE      base.TplName = "user/settings/profile"
+	SETTINGS_AVATAR       base.TplName = "user/settings/avatar"
 	SETTINGS_PASSWORD     base.TplName = "user/settings/password"
 	SETTINGS_EMAILS       base.TplName = "user/settings/email"
 	SETTINGS_SSH_KEYS     base.TplName = "user/settings/sshkeys"
@@ -91,10 +92,6 @@ func SettingsPost(ctx *context.Context, form auth.UpdateProfileForm) {
 	ctx.User.Email = form.Email
 	ctx.User.Website = form.Website
 	ctx.User.Location = form.Location
-	if len(form.Gravatar) > 0 {
-		ctx.User.Avatar = base.EncodeMD5(form.Gravatar)
-		ctx.User.AvatarEmail = form.Gravatar
-	}
 	if err := models.UpdateUser(ctx.User); err != nil {
 		ctx.Handle(500, "UpdateUser", err)
 		return
@@ -106,8 +103,12 @@ func SettingsPost(ctx *context.Context, form auth.UpdateProfileForm) {
 }
 
 // FIXME: limit size.
-func UpdateAvatarSetting(ctx *context.Context, form auth.UploadAvatarForm, ctxUser *models.User) error {
-	ctxUser.UseCustomAvatar = form.Enable
+func UpdateAvatarSetting(ctx *context.Context, form auth.AvatarForm, ctxUser *models.User) error {
+	ctxUser.UseCustomAvatar = form.Source == auth.AVATAR_LOCAL
+	if len(form.Gravatar) > 0 {
+		ctxUser.Avatar = base.EncodeMD5(form.Gravatar)
+		ctxUser.AvatarEmail = form.Gravatar
+	}
 
 	if form.Avatar != nil {
 		fr, err := form.Avatar.Open()
@@ -129,7 +130,7 @@ func UpdateAvatarSetting(ctx *context.Context, form auth.UploadAvatarForm, ctxUs
 	} else {
 		// No avatar is uploaded but setting has been changed to enable,
 		// generate a random one when needed.
-		if form.Enable && !com.IsFile(ctxUser.CustomAvatarPath()) {
+		if ctxUser.UseCustomAvatar && !com.IsFile(ctxUser.CustomAvatarPath()) {
 			if err := ctxUser.GenerateRandomAvatar(); err != nil {
 				log.Error(4, "GenerateRandomAvatar[%d]: %v", ctxUser.ID, err)
 			}
@@ -143,14 +144,20 @@ func UpdateAvatarSetting(ctx *context.Context, form auth.UploadAvatarForm, ctxUs
 	return nil
 }
 
-func SettingsAvatar(ctx *context.Context, form auth.UploadAvatarForm) {
+func SettingsAvatar(ctx *context.Context) {
+	ctx.Data["Title"] = ctx.Tr("settings")
+	ctx.Data["PageIsSettingsAvatar"] = true
+	ctx.HTML(200, SETTINGS_AVATAR)
+}
+
+func SettingsAvatarPost(ctx *context.Context, form auth.AvatarForm) {
 	if err := UpdateAvatarSetting(ctx, form, ctx.User); err != nil {
 		ctx.Flash.Error(err.Error())
 	} else {
 		ctx.Flash.Success(ctx.Tr("settings.update_avatar_success"))
 	}
 
-	ctx.Redirect(setting.AppSubUrl + "/user/settings")
+	ctx.Redirect(setting.AppSubUrl + "/user/settings/avatar")
 }
 
 func SettingsDeleteAvatar(ctx *context.Context) {
@@ -158,7 +165,7 @@ func SettingsDeleteAvatar(ctx *context.Context) {
 		ctx.Flash.Error(err.Error())
 	}
 
-	ctx.Redirect(setting.AppSubUrl + "/user/settings")
+	ctx.Redirect(setting.AppSubUrl + "/user/settings/avatar")
 }
 
 func SettingsPassword(ctx *context.Context) {
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
index 880fca713b..93fc404ba1 100644
--- a/templates/admin/config.tmpl
+++ b/templates/admin/config.tmpl
@@ -215,6 +215,12 @@
 						<dd><i class="fa fa{{if .DisableGravatar}}-check{{end}}-square-o"></i></dd>
 					</dl>
 				</div>
+				<div class="ui attached table segment">
+					<dl class="dl-horizontal admin-dl-horizontal">
+						<dt>{{.i18n.Tr "admin.config.enable_federated_avatar"}}</dt>
+						<dd><i class="fa fa{{if .EnableFederatedAvatar}}-check{{end}}-square-o"></i></dd>
+					</dl>
+				</div>
 
 				<h4 class="ui top attached header">
 					{{.i18n.Tr "admin.config.log_config"}}
diff --git a/templates/install.tmpl b/templates/install.tmpl
index b3d4d7339d..496c425654 100644
--- a/templates/install.tmpl
+++ b/templates/install.tmpl
@@ -177,6 +177,12 @@
 									<input name="disable_gravatar" type="checkbox" {{if .disable_gravatar}}checked{{end}}>
 								</div>
 							</div>
+							<div class="inline field">
+								<div class="ui checkbox" id="federated-avatar-lookup">
+									<label class="poping up" data-content="{{.i18n.Tr "install.federated_avatar_lookup"}}"><strong>{{.i18n.Tr "install.federated_avatar_lookup"}}</strong></label>
+									<input name="enable_federated_avatar" type="checkbox" {{if .enable_federated_avatar}}checked{{end}}>
+								</div>
+							</div>
 							<div class="inline field">
 								<div class="ui checkbox" id="disable-registration">
 									<label class="poping up" data-content="{{.i18n.Tr "install.disable_registration_popup"}}"><strong>{{.i18n.Tr "install.disable_registration"}}</strong></label>
diff --git a/templates/user/settings/avatar.tmpl b/templates/user/settings/avatar.tmpl
new file mode 100644
index 0000000000..926c9d8508
--- /dev/null
+++ b/templates/user/settings/avatar.tmpl
@@ -0,0 +1,50 @@
+{{template "base/head" .}}
+<div class="user settings avatar">
+	<div class="ui container">
+		<div class="ui grid">
+			{{template "user/settings/navbar" .}}
+			<div class="twelve wide column content">
+				{{template "base/alert" .}}
+				<h4 class="ui top attached header">
+					{{.i18n.Tr "settings.avatar"}}
+				</h4>
+				<div class="ui attached segment">
+
+					<form class="ui form" action="{{.Link}}" method="post" enctype="multipart/form-data">
+						{{.CsrfTokenHtml}}
+						{{if not DisableGravatar}}
+						<div class="inline field">
+							<div class="ui radio">
+								<input name="source" value="lookup" type="radio" {{if not .SignedUser.UseCustomAvatar}}checked{{end}}>
+								<label>{{.i18n.Tr "settings.lookup_avatar_by_mail"}}</label>
+							</div>
+						</div>
+						<div class="field {{if .Err_Gravatar}}error{{end}}">
+							<label for="gravatar">Avatar {{.i18n.Tr "email"}}</label>
+							<input id="gravatar" name="gravatar" value="{{.SignedUser.AvatarEmail}}" />
+						</div>
+						{{end}}
+
+						<div class="inline field">
+							<div class="ui radio">
+								<input name="source" value="local" type="radio" {{if .SignedUser.UseCustomAvatar}}checked{{end}}>
+								<label>{{.i18n.Tr "settings.enable_custom_avatar"}}</label>
+							</div>
+						</div>
+
+						<div class="inline field">
+							<label for="avatar">{{.i18n.Tr "settings.choose_new_avatar"}}</label>
+							<input name="avatar" type="file" >
+						</div>
+
+						<div class="field">
+							<button class="ui green button">{{$.i18n.Tr "settings.update_avatar"}}</button>
+							<a class="ui red button delete-post" data-request-url="{{.Link}}/delete" data-done-url="{{.Link}}">{{$.i18n.Tr "settings.delete_current_avatar"}}</a>
+						</div>
+					</form>
+				</div>
+			</div>
+		</div>
+	</div>
+</div>
+{{template "base/footer" .}}
diff --git a/templates/user/settings/navbar.tmpl b/templates/user/settings/navbar.tmpl
index 87e24522b4..5166bafaba 100644
--- a/templates/user/settings/navbar.tmpl
+++ b/templates/user/settings/navbar.tmpl
@@ -4,6 +4,9 @@
 		<a class="{{if .PageIsSettingsProfile}}active{{end}} item" href="{{AppSubUrl}}/user/settings">
 			{{.i18n.Tr "settings.profile"}}
 		</a>
+		<a class="{{if .PageIsSettingsAvatar}}active{{end}} item" href="{{AppSubUrl}}/user/settings/avatar">
+			{{.i18n.Tr "settings.avatar"}}
+		</a>
 		<a class="{{if .PageIsSettingsPassword}}active{{end}} item" href="{{AppSubUrl}}/user/settings/password">
 			{{.i18n.Tr "settings.password"}}
 		</a>
diff --git a/templates/user/settings/profile.tmpl b/templates/user/settings/profile.tmpl
index a1328a2210..a42d9c49c3 100644
--- a/templates/user/settings/profile.tmpl
+++ b/templates/user/settings/profile.tmpl
@@ -35,38 +35,12 @@
 							<label for="location">{{.i18n.Tr "settings.location"}}</label>
 							<input id="location" name="location"  value="{{.SignedUser.Location}}">
 						</div>
-						{{if not DisableGravatar}}
-						<div class="field {{if .Err_Gravatar}}error{{end}}">
-							<label for="gravatar">Gravatar {{.i18n.Tr "email"}}</label>
-							<input id="gravatar" name="gravatar" value="{{.SignedUser.AvatarEmail}}" />
-						</div>
-						{{end}}
 
 						<div class="field">
 							<button class="ui green button">{{$.i18n.Tr "settings.update_profile"}}</button>
 						</div>
 					</form>
 
-					<div class="ui divider"></div>
-
-					<form class="ui form" action="{{.Link}}/avatar" method="post" enctype="multipart/form-data">
-						{{.CsrfTokenHtml}}
-						<div class="inline field">
-							<div class="ui checkbox">
-								<input name="enable" type="checkbox" {{if .SignedUser.UseCustomAvatar}}checked{{end}}>
-								<label>{{.i18n.Tr "settings.enable_custom_avatar"}}</label>
-							</div>
-						</div>
-						<div class="inline field">
-							<label for="avatar">{{.i18n.Tr "settings.choose_new_avatar"}}</label>
-							<input name="avatar" type="file" >
-						</div>
-
-						<div class="field">
-							<button class="ui green button">{{$.i18n.Tr "settings.update_avatar"}}</button>
-							<a class="ui red button delete-post" data-request-url="{{.Link}}/avatar/delete" data-done-url="{{.Link}}">{{$.i18n.Tr "settings.delete_current_avatar"}}</a>
-						</div>
-					</form>
 				</div>
 			</div>
 		</div>