Running Tomcat Stand-alone on Port 80 Jason Brittain Co-author of Tomcat: The Definitive Guide (O'Reilly) Software Architect, MuleSoft Tcat Server Why run Tomcat on port 80? Running Tomcat Stand-alone on Port 80: Reasons - When you're not load balancing - When you want Tomcat's full performance - When you want straightforward easy configurations - When the firewall needs it to actually be on port 80 (You can rename this presentation substituting any privileged port number, such as 443) - When you need/want to serve directly from any port lower than 1024 Issues with running Java on privileged ports - Windows: None. Windows works perfectly! - Linux: Need special system user permission - Solaris: Need special system user permission - MacOS X: Need to be an administrator-class user (first user on the machine is the primary administrator) Suboptimal Solutions - Run Tomcat as root - Run Tomcat "behind" Apache httpd or another web server, proxy everything - Switch server operating systems to Windows Generic Solutions - NAT port remapping: Map network packets destined for 80 to Tomcat's unprivileged server port - Superuser function overriding: Start the process as root, remap the server socket bind() function, then fork and setuid down to the Tomcat user - Fine grained user permissions: Grant a finegrained system user permission to allow the Tomcat user's JVM to open a privileged server port Linux, Solaris, MacOS solution: jsvc Starting: # ./jsvc -user tomcat -home /usr/java/latest -wait 10 pidfile /var/run/jsvc.pid -outfile /opt/tomcat/logs/catalina.out -errfile /opt/tomcat/logs/catalina.out Dcatalina.base=/opt/tomcat Dcatalina.home=/opt/tomcat -Dmore=props... org.apache.catalina.startup.Bootstrap start Stopping: # ./jsvc -stop -pidfile /var/run/jsvc.pid org.apache.catalina.startup.Bootstrap Linux, Solaris, MacOS solution: jsvc Advantages - Does not require any firewall rules to be changed - Generic solution is multiplatform - Zero server performance degredation - Server lockup detection & auto JVM restarts - Supports both IPv4 and IPv6 Linux, Solaris, MacOS solution: jsvc Disadvantages - Requires starting Tomcat with sudo or as the root user - Sometimes causes Tomcat JVM restart failures - Can cause inadvertent/unintentional Tomcat JVM restarts - Complicates Tomcat server startup scripting - Native code, can't tar it up and move it to a different OS/architecture Linux port 80 solution: iptables Linux port 80 solution: iptables # Remap packets coming from outside the machine. iptables -t nat -I PREROUTING -p tcp --dst 192.168.1.100 --dport 80 -j REDIRECT --toports 8080 # Remap packets coming from inside the machine. iptables -t nat -I OUTPUT -p tcp --dst 192.168.1.100 --dport 80 -j REDIRECT --toports 8080 Linux port 80 solution: iptables - Happens in Linux Kernel space, not user space - Highly efficient - Layer 4 switching: Transport Layer of OSI model - Does not require starting Tomcat with sudo nor as root - Generic solution is multiplatform - Well supported across Linux distributions - Supports both IPv4 and IPv6 - Almost always preinstalled Linux port 80 solution: iptables Disadvantages - Requires sudo privilege or root to add the iptables rule(s) - iptables is Linux-only, but similar tools exist on the other OSs - Requires dealing with iptables "firewall" rules syntax - Difficult to troubleshoot (network engineering) Linux port 80 solution: authbind # authbind --deep /bin/bash -c 'set -a; source "$DEFAULT"; $CATALINA_HOME/bin/catalina.sh start' - Yet unassessed / unbenchmarked performance penalty - On Debian and Ubuntu: Can be installed along with Tomcat as part of the OS Linux port 80 solution: authbind Disadvantages - GPL'd, and usually not preinstalled as part of the OS - Requires starting Tomcat with sudo or as the root user - Not a multiplatform solution, Linux-only - IPv4 only - APR connector doesn't necessarily work with it - Ports from 512 to 1023 inclusive cannot be used Linux port 80 solution: POSIX Capabilities $ sudo -s # yum install patchelf # Or download from http://nixos.org/patchelf.html # export JAVA_HOME=/usr/java/jdk1.7.0 # patchelf --set-rpath $JAVA_HOME/jre/lib/i386/jli $JAVA_HOME/bin/java # setcap 'cap_net_bind_service=+ep' $JAVA_HOME/bin/java .. then run Tomcat as any user! Linux port 80 solution: POSIX Capabilities - Fine grained user permission for binding to privileged ports - Seems like the "right way" - Zero server performance degredation - Does not require starting Tomcat with sudo nor as root - Generic solution is multiplatform - Well supported across Linux distributions - Supports both IPv4 and IPv6 Linux port 80 solution: POSIX Capabilities Disadvantages - Java 1.7 only (OpenJDK 1.7.0 EA works), 1.6 is broken http://bugs.sun.com/bugdatabase/view_bug.do?b ug_id=6919633 - Doesn't work with alternate JVMs (JRockit & J9) - Requires sudo privilege or root to enable bind capability via setcap - Must install patchelf, or deploy only the patchelf-patched JDK binary - JDK binaries not path movable after the change Solaris port 80 solution: ipf Edit ipnat.conf and add: # Redirect port 80 to 8080 rdr eri0 1.2.3.4/32 port 80 -> 1.2.3.4 port 8080 tcp Then run: # ipfboot reload Solaris port 80 solution: ipf Advantages - Same as those of Linux iptables, but Solaris-only implementation Solaris port 80 solution: ipf Disadvantages - Requires sudo privilege or root to add the ipf rule(s) - ipf is Solaris-only, but similar tools exist on the other OSs - Requires dealing with ipf firewall rules syntax - Difficult to troubleshoot (network engineering) Solaris port 80 solution: User Privileges # usermod -K defaultpriv=basic,net_privadd tomcat .. then run Tomcat as user 'tomcat'. - Same advantages as POSIX capabilities Solaris port 80 solution: User Privileges Disadvantages - Requires sudo privilege or root to enable bind capability via usermod MacOS X port 80 solution: ipfw $ sudo ipfw add 100 fwd 127.0.0.1,8080 tcp from any to any 80 in - Same advantages as Linux iptables and Solaris ipf - Same disadvantages as Linux iptables and Solaris ipf Thanks! Slides: http://www.brittainweb.org/jason/tomcat-on-port-80-apachecon-na-2010.ppt Links MuleSoft Tcat Server: Enterprise Tomcat Made Simple http://www.mulesoft.com/tcat-server-enterprise-tomcatapplication-server Apache Commons Daemon: jsvc http://commons.apache.org/daemon privbind: Run unprivileged processes that can bind to privileged TCP/UDP ports http://sf.net/projects/privbind Links (continued) Is there a way for non-root processes to bind to privileged ports lower than 1024 on Linux? http://stackoverflow.com/questions/413807/is-there-a-way-fornon-root-processes-to-bind-to-privileged-ports-1024-on-linux Using IPTables to Redirect Port 80 to Port 8080 http://rifers.org/wiki/display/RIFE/Installing+Tomcat+on+port+80+ with+iptables Bind ports below 1024 without root on GNU/Linux http://www.wensley.org.uk/info#setpcaps Links (continued) Java doesn't support POSIX File Capabilities (A.K.A. Linux Capabilities) http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6919633 patchelf http://nixos.org/patchelf.html