diff --git a/CHANGELOG b/CHANGELOG
index d0a796fb4cf08b88e9cabf3422f37fb2228f7440..3fa5143d43ffbc253694153cb8baf6666f4eec6c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,6 +8,7 @@ v 6.4.0
   - Internal projects (Jason Hollingsworth)
   - Allow removal of avatar (Drew Blessing)
   - Project web hooks now support issues and merge request events
+  - Visiting project page while not logged in will redirect to sign-in instead of 404 (Jason Hollingsworth)
 
 v 6.3.0
   - API for adding gitlab-ci service
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index a83d6dfed8dfe016c9488851661c076cd2cdf58e..e5b5a3a47778e95f93d7a87578d83eae6e991d47 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -81,6 +81,9 @@ class ApplicationController < ActionController::Base
 
     if @project and can?(current_user, :read_project, @project)
       @project
+    elsif current_user.nil?
+      @project = nil
+      authenticate_user!
     else
       @project = nil
       render_404 and return
diff --git a/features/project/redirects.feature b/features/project/redirects.feature
new file mode 100644
index 0000000000000000000000000000000000000000..ce197912f641f9c412ec24631441c17d99eb64ba
--- /dev/null
+++ b/features/project/redirects.feature
@@ -0,0 +1,26 @@
+Feature: Project Redirects
+  Background:
+    Given public project "Community"
+    And private project "Enterprise"
+
+  Scenario: I visit public project page
+    When I visit project "Community" page
+    Then I should see project "Community" home page
+
+  Scenario: I visit private project page
+    When I visit project "Enterprise" page
+    Then I should be redirected to sign in page
+
+  Scenario: I visit a non-existent project page
+    When I visit project "CommunityDoesNotExist" page
+    Then I should be redirected to sign in page
+
+  Scenario: I visit a non-existent project page as user
+    Given I sign in as a user
+    When I visit project "CommunityDoesNotExist" page
+    Then page status code should be 404
+
+  Scenario: I visit unauthorized project page as user
+    Given I sign in as a user
+    When I visit project "Enterprise" page
+    Then page status code should be 404
diff --git a/features/public/public_projects.feature b/features/public/public_projects.feature
index 03825dffd3ff36f47189113a4c1bc49a24762b9c..5a30c03dd4a5609b53b6e79f1147ab777227862a 100644
--- a/features/public/public_projects.feature
+++ b/features/public/public_projects.feature
@@ -16,11 +16,11 @@ Feature: Public Projects Feature
 
   Scenario: I visit internal project page
     When I visit project "Internal" page
-    Then page status code should be 404
+    Then I should be redirected to sign in page
 
   Scenario: I visit private project page
     When I visit project "Enterprise" page
-    Then page status code should be 404
+    Then I should be redirected to sign in page
 
   Scenario: I visit an empty public project page
     Given public empty project "Empty Public Project"
diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb
index 3e4a105ec5571a7c28e7d659d08e2caa6eac618a..a72f8a44f96ee74c3fe80f8c49e077b0ac7e2bf7 100644
--- a/features/steps/profile/profile.rb
+++ b/features/steps/profile/profile.rb
@@ -88,10 +88,6 @@ class Profile < Spinach::FeatureSteps
     page.should have_content "Password doesn't match confirmation"
   end
 
-  step 'I should be redirected to sign in page' do
-    current_path.should == new_user_session_path
-  end
-
   step 'I reset my token' do
     within '.update-token' do
       @old_token = @user.private_token
diff --git a/features/steps/project/redirects.rb b/features/steps/project/redirects.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4ac53075704281407fa200f82a351d8449a6e0ef
--- /dev/null
+++ b/features/steps/project/redirects.rb
@@ -0,0 +1,35 @@
+class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
+  include SharedAuthentication
+  include SharedPaths
+  include SharedProject
+
+  step 'public project "Community"' do
+    create :project_with_code, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC
+  end
+
+  step 'private project "Enterprise"' do
+    create :project, name: 'Enterprise'
+  end
+
+  step 'I visit project "Community" page' do
+    project = Project.find_by_name('Community')
+    visit project_path(project)
+  end
+
+  step 'I should see project "Community" home page' do
+    within '.project-home-title' do
+      page.should have_content 'Community'
+    end
+  end
+
+  step 'I visit project "Enterprise" page' do
+    project = Project.find_by_name('Enterprise')
+    visit project_path(project)
+  end
+
+  step 'I visit project "CommunityDoesNotExist" page' do
+    project = Project.find_by_name('Community')
+    visit project_path(project) + 'DoesNotExist'
+  end
+end
+
diff --git a/features/steps/shared/authentication.rb b/features/steps/shared/authentication.rb
index 8c501bbc537edf281c1af5443f2dd2a522d0b987..df05754c287d3a6bf984b4c2a7ddd283032338da 100644
--- a/features/steps/shared/authentication.rb
+++ b/features/steps/shared/authentication.rb
@@ -12,6 +12,10 @@ module SharedAuthentication
     login_as :admin
   end
 
+  step 'I should be redirected to sign in page' do
+    current_path.should == new_user_session_path
+  end
+
   def current_user
     @user || User.first
   end