diff --git src/simutrans/ground/grund.cc src/simutrans/ground/grund.cc
index ac11a81bf..5022212fd 100644
--- src/simutrans/ground/grund.cc
+++ src/simutrans/ground/grund.cc
@@ -1774,6 +1774,10 @@ void grund_t::display_overlay(const sint16 xpos, const sint16 ypos)
 				}
 
 				if( signal_t* sig = find<signal_t>() ) {
+					if (sig->get_two_ways()) {
+						// Display only one arrow if needed
+						mask = sig->get_dir();
+					}
 					if( sig->get_state()==roadsign_t::signalstate::STATE_RED ) {
 						c1 = gfx->palette_lookup( COL_ORANGE+2 );
 						c2 = gfx->palette_lookup( COL_ORANGE );
diff --git src/simutrans/gui/signal_info.cc src/simutrans/gui/signal_info.cc
index 3ee93c049..857b4d5fe 100644
--- src/simutrans/gui/signal_info.cc
+++ src/simutrans/gui/signal_info.cc
@@ -11,11 +11,17 @@
 
 #include "../tool/simmenu.h"
 #include "../world/simworld.h"
+#include "../dataobj/ribi.h"
 
 signal_info_t::signal_info_t(signal_t *s) :
 	obj_infowin_t(s),
 	sig(s)
 {
+	two_ways_toggle.init( button_t::square_state, "allow trains both ways");
+	two_ways_toggle.add_listener( this );
+	two_ways_toggle.pressed = sig->get_two_ways();
+	add_component( &two_ways_toggle );
+
 	remove.init( button_t::roundbox, "remove signal");
 	remove.add_listener( this );
 	add_component( &remove );
@@ -31,22 +37,38 @@ signal_info_t::signal_info_t(signal_t *s) :
 }
 
 
-bool signal_info_t::action_triggered( gui_action_creator_t *, value_t /* */)
+bool signal_info_t::action_triggered( gui_action_creator_t *comp, value_t /* */)
 {
-	bool suspended_execution=false;
-	koord3d pos = sig->get_pos();
-	tool_t::general_tool[TOOL_REMOVE_SIGNAL]->set_default_param(NULL);
-	const char *err = welt->call_work_api( tool_t::general_tool[TOOL_REMOVE_SIGNAL], welt->get_active_player(), pos, suspended_execution);
-	if(!suspended_execution) {
-		// play sound / error message
-		welt->get_active_player()->tell_tool_result(tool_t::general_tool[TOOL_REMOVE_SIGNAL], pos, err);
+	if (comp == &remove) {
+		bool suspended_execution=false;
+		koord3d pos = sig->get_pos();
+		tool_t::general_tool[TOOL_REMOVE_SIGNAL]->set_default_param(NULL);
+		const char *err = welt->call_work_api( tool_t::general_tool[TOOL_REMOVE_SIGNAL], welt->get_active_player(), pos, suspended_execution);
+		if(!suspended_execution) {
+			// play sound / error message
+			welt->get_active_player()->tell_tool_result(tool_t::general_tool[TOOL_REMOVE_SIGNAL], pos, err);
+		}
+	} else if (comp == &two_ways_toggle) {
+		char param[64];
+		sprintf(param, "%s,1,%u", sig->get_pos().get_str(), !two_ways_toggle.pressed);
+		tool_t::simple_tool[TOOL_CHANGE_TRAFFIC_LIGHT]->set_default_param(param);
+		welt->set_tool(tool_t::simple_tool[TOOL_CHANGE_TRAFFIC_LIGHT], welt->get_active_player());
+		two_ways_toggle.pressed = sig->get_two_ways();
 	}
 	return true;
 }
 
 
+// notify for an external update
+void signal_info_t::update_data()
+{
+	two_ways_toggle.pressed = sig->get_two_ways();
+}
+
+
 void signal_info_t::draw( scr_coord pos, scr_size size )
 {
+	two_ways_toggle.enable( ribi_t::is_single(sig->get_dir()) );
 	remove.enable( !sig->get_removal_error( welt->get_active_player() ) );
 	obj_infowin_t::draw( pos, size );
 }
diff --git src/simutrans/gui/signal_info.h src/simutrans/gui/signal_info.h
index f0709f14b..72df5cff1 100644
--- src/simutrans/gui/signal_info.h
+++ src/simutrans/gui/signal_info.h
@@ -21,6 +21,7 @@ class signal_t;
 class signal_info_t : public obj_infowin_t, public action_listener_t
 {
  private:
+	button_t two_ways_toggle;
 	button_t remove;
 	signal_t *sig;
 
@@ -30,6 +31,7 @@ class signal_info_t : public obj_infowin_t, public action_listener_t
 	const char *get_help_filename() const OVERRIDE {return "signal_info.txt";}
 
 	bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE;
+	void update_data();
 
 	void draw( scr_coord pos, scr_size size ) OVERRIDE;
 };
diff --git src/simutrans/obj/roadsign.cc src/simutrans/obj/roadsign.cc
index c18f899de..f153b757b 100644
--- src/simutrans/obj/roadsign.cc
+++ src/simutrans/obj/roadsign.cc
@@ -89,6 +89,9 @@ roadsign_t::roadsign_t(player_t *player, koord3d pos, ribi_t::ribi dir, const ro
 			ticks_offset = 1 << player->get_player_nr();
 		}
 	}
+	if(  desc->is_signal_type()  ) {
+		set_two_ways(false);
+	}
 	/* if more than one state, we will switch direction and phase for traffic lights
 	 * however also gate signs need indications
 	 */
@@ -112,7 +115,7 @@ roadsign_t::~roadsign_t()
 				finance_waytype = weg->get_waytype();
 
 				if (!preview) {
-					if (desc->is_single_way()  ||  desc->is_signal_type()) {
+					if (desc->is_single_way()  ||  (desc->is_signal_type() && !get_two_ways())) {
 						// signal removed, remove direction mask
 						weg->set_ribi_maske(ribi_t::none);
 					}
@@ -143,7 +146,7 @@ void roadsign_t::set_dir(ribi_t::ribi dir)
 		if(  desc->get_wtyp()!=track_wt  &&  desc->get_wtyp()!=monorail_wt  &&  desc->get_wtyp()!=maglev_wt  &&  desc->get_wtyp()!=narrowgauge_wt  ) {
 			weg->count_sign();
 		}
-		if(desc->is_single_way()  ||  desc->is_signal_type()) {
+		if(desc->is_single_way()  ||  (desc->is_signal_type() && !get_two_ways())) {
 			// set mask, if it is a single way ...
 			weg->count_sign();
 			weg->set_ribi_maske(calc_mask());
@@ -168,6 +171,20 @@ DBG_MESSAGE("roadsign_t::set_dir()","ribi %i",dir);
 }
 
 
+void roadsign_t::set_two_ways(bool yesno)
+{
+	 ticks_ns = yesno ? 1 : 0;
+	 if(desc->is_signal_type()) {
+		 // Mask needs a change
+		 weg_t *weg = welt->lookup(get_pos())->get_weg(desc->get_wtyp()!=tram_wt ? desc->get_wtyp() : track_wt);
+		 if (weg) {
+			 weg->count_sign();
+			 weg->set_ribi_maske(yesno ? ribi_t::none : calc_mask());
+		 }
+	 }
+}
+
+
 void roadsign_t::show_info()
 {
 	if(  desc->is_private_way()  ) {
@@ -644,6 +661,9 @@ void roadsign_t::rdwr(loadsave_t *file)
 				ticks_ns = 0xFF;
 			}
 		}
+		if(  desc  &&  desc->is_signal_type()  &&  file->is_version_less(124, 4)  ) {
+			ticks_ns = 0;
+		}
 	}
 }
 
diff --git src/simutrans/obj/roadsign.h src/simutrans/obj/roadsign.h
index ce73637f1..14beb9073 100644
--- src/simutrans/obj/roadsign.h
+++ src/simutrans/obj/roadsign.h
@@ -28,7 +28,7 @@ protected:
 	image_id foreground_image;
 
 	enum {
-		SHOW_FONT        = 1,
+		SHOW_FRONT       = 1,
 		SHOW_BACK        = 2,
 		SWITCH_AUTOMATIC = 16
 	};
@@ -38,9 +38,16 @@ protected:
 
 	uint8 automatic:1;
 	uint8 preview:1;
+
+	/*
+	 * Many things go in these...
+	 *   Traffic lights -> intended usage
+	 *   Private way signs -> bits go in ticks_ow (MSB) and ticks_iffset (LSB)
+	 *   Signals -> two_ways state goes in ticks_ns
+	 */
 	uint8 ticks_ns;
 	uint8 ticks_ow;
-        uint8 ticks_yellow_ns, ticks_yellow_ow;
+	uint8 ticks_yellow_ns, ticks_yellow_ow;
 	uint8 ticks_offset;
 
 	sint8 after_yoffset, after_xoffset;
@@ -69,6 +76,12 @@ public:
 	*/
 	void set_dir(ribi_t::ribi dir);
 
+	/*
+	 * Only makes sense for signals!
+	 */
+	bool get_two_ways() const { return ticks_ns != 0; }
+	void set_two_ways(bool yesno);
+
 	void set_state(signalstate z) {state = z; calc_image();}
 	signalstate get_state() { return (signalstate)state; }
 
diff --git src/simutrans/tool/simtool.cc src/simutrans/tool/simtool.cc
index 2831e78a7..17394cd84 100644
--- src/simutrans/tool/simtool.cc
+++ src/simutrans/tool/simtool.cc
@@ -52,6 +52,7 @@
 #include "../gui/city_info.h"
 #include "../gui/trafficlight_info.h"
 #include "../gui/privatesign_info.h"
+#include "../gui/signal_info.h"
 #include "../gui/messagebox.h"
 
 #include "../network/network_socket_list.h"
@@ -8499,6 +8500,17 @@ bool tool_change_traffic_light_t::init( player_t *player )
 				}
 			}
 		}
+		else if ( signal_t *sig = gr->find<signal_t>() ) {
+			if (player_t::check_owner(sig->get_owner(), player)) {
+				if (ns == 1) {
+					sig->set_two_ways(ticks);
+				}
+				signal_info_t* signal_win = (signal_info_t*)win_get_magic((ptrdiff_t)sig);
+				if (signal_win) {
+					signal_win->update_data();
+				}
+			}
+		}
 	}
 	return false;
 }
diff --git src/simutrans/vehicle/rail_vehicle.cc src/simutrans/vehicle/rail_vehicle.cc
index 3d88546e3..9981ef217 100644
--- src/simutrans/vehicle/rail_vehicle.cc
+++ src/simutrans/vehicle/rail_vehicle.cc
@@ -755,11 +755,15 @@ bool rail_vehicle_t::block_reserver(const route_t *route, route_t::index_t start
 #endif
 		if(reserve) {
 			if(  sch1->has_signal()  &&  i<route->get_count()-1  ) {
-				if(count) {
-					signs.append(gr);
+				signal_t* signal = gr->find<signal_t>();
+				// Maybe we can ignore the signal
+				if (!( signal->get_two_ways() && i>start_index && !(ribi_type(pos, route->at(i-1)) & signal->get_dir()) )) {
+					if (count) {
+						signs.append(gr);
+					}
+					count --;
+					next_signal_index = i;
 				}
-				count --;
-				next_signal_index = i;
 			}
 			if (!sch1->reserve(cnv->self, ribi_type(route->at(max(1u, i) - 1u), route->at(min(route->get_count() - 1u, i + 1u))))) {
 				success = false;
