Get Site URL from apex

#NotAnApi

But with some cunning, you can extract this from the site debug mode endpoint:

String name = 'mysite';

Site site = [
    SELECT GuestUserId
    FROM Site
    WHERE Name = :name
];

String path = '/sites/servlet.SiteDebugMode';
PageReference pr = new PageReference(path);
pr.getParameters().put('guid', site.GuestUserId);
pr.getParameters().put('sitedebugmode', 'x');
String url = pr.getContent().toString().substringAfter('URL=').substringBefore(path);

System.debug(url); //eg "http://dev-bigass.cs81.force.com/mysite"

Seems to behave across environments regardless of Production / Sandbox / My Domain etc.


Since Winter '17 (v38.0)

You can get the secureURL using the SiteDetail object

Site mySite = [select Id from Site where Name = 'MySite'];
SiteDetail mySiteDetail = [select SecureURL from SiteDetail where DurableId = :mySite.Id];
System.debug(mySiteDetail.SecureURL);

This doesn't seem to be possible from apex, I ended up trying the different ways described above, and decided to go with a Custom Setting. I added the Custom Setting Site URL which needs to be filled in every time when the app gets configured.