diff --git a/.gitignore b/.gitignore
index f4d93b9805005e13d8877a948b920de87afebbd1..1cdb44484d5231d41906731749fef5f11ee177ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+deploy-latest.sh
 app.yaml
 settings.py
 initialization.py
diff --git a/fabfile.py b/fabfile.py
index 690b31992d2a1f93d2652de98d3f238412cde6b0..4d2554af3fea25647687f9ae2023fb7ed9db8500 100644
--- a/fabfile.py
+++ b/fabfile.py
@@ -41,7 +41,7 @@ PRODUCTION_SETUPS = [
         'root' : "/web/princeton/helios-server",
         'celery' : "/etc/init.d/princeton-celeryd",
         'dbname' : "princeton-helios"
-        },
+        }
 ]
         
 def run_tests():
@@ -101,13 +101,11 @@ def restart_apache():
         abort("could not restart apache")
 
 def restart_celeryd(path):
-    result = sudo('%s restart' % celery_path)
+    result = sudo('%s restart' % path)
     if result.failed:
-        abort("could not restart celeryd - %s " % celery_path)
+        abort("could not restart celeryd - %s " % path)
 
 def deploy(tag, path):
-    confirm("Ready to deploy %s to %s?" % (tag,path))
-    run_tests()
     if tag == 'latest':
         get_latest(path=path)
     else:
@@ -120,6 +118,10 @@ def staging_deploy(tag):
     deploy(tag, path=STAGING_SETUP['root'])
 
 def production_deploy(tag):
+    production_roots = ",".join([p['root'] for p in PRODUCTION_SETUPS])
+    if not confirm("Ready to deploy %s to %s?" % (tag, production_roots)):
+        return
+    run_tests()
     for prod_setup in PRODUCTION_SETUPS:
         deploy(tag, path = prod_setup['root'])
         restart_celeryd(path = prod_setup['celery'])
diff --git a/helios/security.py b/helios/security.py
index 7abbf329858591f01ee1e94cadd27ddc8213306d..50e4a03d50e94230b7864c27d35253bf1b97b950 100644
--- a/helios/security.py
+++ b/helios/security.py
@@ -15,6 +15,7 @@ from models import *
 from auth.security import get_user
 
 from django.http import HttpResponseRedirect
+import urllib
 
 import helios
 
@@ -82,8 +83,10 @@ def election_view(**checks):
         from views import get_voter, get_user, password_voter_login
         user = get_user(request)
         if not user_can_admin_election(user, election) and not get_voter(request, user, election):
-          # FIXME: should be a nice redirect
-          return HttpResponseRedirect(reverse(password_voter_login, args=[election.uuid]))
+          return_url = request.get_full_path()
+          return HttpResponseRedirect("%s?%s" % (reverse(password_voter_login, args=[election.uuid]), urllib.urlencode({
+                  'return_url' : return_url
+                  })))
     
       return func(request, election, *args, **kw)
 
diff --git a/helios/templates/_castconfirm_password.html b/helios/templates/_castconfirm_password.html
index e95543a8a2f0d183372c18a218ac483cf4b0de9d..4b1abc5a678d5e69d852e5d8a97b187d7ada2144 100644
--- a/helios/templates/_castconfirm_password.html
+++ b/helios/templates/_castconfirm_password.html
@@ -1,6 +1,7 @@
 Please provide the voter ID and password you received by email.<br /><br />
 <form method="post" action="{% url helios.views.password_voter_login election.uuid %}">
 <input type="hidden" name="csrf_token" value="{{csrf_token}}" />
+<input type="hidden" name="return_url" value="{{return_url}}" />
 <table>
     {{password_login_form.as_table}}
 </table>
diff --git a/helios/views.py b/helios/views.py
index 47921fbbf276d570699945d17817ed8b5db6b133..119575baf8ff0e3e950d711af8fb22828e8363eb 100644
--- a/helios/views.py
+++ b/helios/views.py
@@ -155,14 +155,19 @@ def election_shortcut(request, election_short_name):
   else:
     raise Http404
 
+# a hidden view behind the shortcut that performs the actual perm check
+@election_view()
+def _election_vote_shortcut(request, election):
+  vote_url = "%s/booth/vote.html?%s" % (settings.SECURE_URL_HOST, urllib.urlencode({'election_url' : reverse(one_election, args=[election.uuid])}))
+  
+  test_cookie_url = "%s?%s" % (reverse(test_cookie), urllib.urlencode({'continue_url' : vote_url}))
+
+  return HttpResponseRedirect(test_cookie_url)
+  
 def election_vote_shortcut(request, election_short_name):
   election = Election.get_by_short_name(election_short_name)
   if election:
-    vote_url = "%s/booth/vote.html?%s" % (settings.SECURE_URL_HOST, urllib.urlencode({'election_url' : reverse(one_election, args=[election.uuid])}))
-
-    test_cookie_url = "%s?%s" % (reverse(test_cookie), urllib.urlencode({'continue_url' : vote_url}))
-
-    return HttpResponseRedirect(test_cookie_url)
+    return _election_vote_shortcut(request, election_uuid=election.uuid)
   else:
     raise Http404
 
@@ -542,18 +547,25 @@ def password_voter_login(request, election):
   This is used to log in as a voter for a particular election
   """
 
+  # the URL to send the user to after they've logged in
+  return_url = request.REQUEST.get('return_url', reverse(one_election_cast_confirm, args=[election.uuid]))
   if request.method == "GET":
     password_login_form = forms.VoterPasswordForm()
-    return render_template(request, 'password_voter_login', {'election': election, 'password_login_form': password_login_form})
+    return render_template(request, 'password_voter_login', {'election': election, 
+                                                             'return_url' : return_url,
+                                                             'password_login_form': password_login_form})
 
-  password_login_form = forms.VoterPasswordForm(request.POST)
+  login_url = request.REQUEST.get('login_url', None)
 
-  # redirect base depending on whether this is a private election
-  # cause if it's private the login is happening on the front page
-  if election.private_p:
-    redirect_base = reverse(one_election_view, args=[election.uuid])
-  else:
-    redirect_base = reverse(one_election_cast_confirm, args=[election.uuid])
+  if not login_url:
+    # login depending on whether this is a private election
+    # cause if it's private the login is happening on the front page
+    if election.private_p:
+      login_url = reverse(one_election_view, args=[election.uuid])
+    else:
+      login_url = reverse(one_election_cast_confirm, args=[election.uuid])
+
+  password_login_form = forms.VoterPasswordForm(request.POST)
 
   if password_login_form.is_valid():
     try:
@@ -562,9 +574,9 @@ def password_voter_login(request, election):
 
       request.session['CURRENT_VOTER'] = voter
     except Voter.DoesNotExist:
-        return HttpResponseRedirect(redirect_base + "?bad_voter_login=1")
+      return HttpResponseRedirect(login_url + "?bad_voter_login=1")
   
-  return HttpResponseRedirect(redirect_base)
+  return HttpResponseRedirect(return_url)
 
 @election_view(frozen=True)
 def one_election_cast_confirm(request, election):