├── .dockerignore ├── .gitignore ├── Dockerfile ├── README.md ├── build.sh ├── configuration ├── basic.cfg └── server.cfg ├── debug.sh ├── profiles └── home │ └── server │ └── server.Arma3Profile ├── run.sh └── scripts ├── startserver └── startup /.dockerignore: -------------------------------------------------------------------------------- 1 | ./debug.sh 2 | ./run.sh 3 | ./build.sh 4 | ./README.md 5 | ./keys/id_rsa 6 | ./.gitignore 7 | ./.git/ 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | keys 2 | credentials.sh 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM adamveld12/steam 2 | 3 | MAINTAINER Adam Veldhousen "adam@veldhousen.ninja" 4 | 5 | WORKDIR /home/steam 6 | 7 | RUN mkdir -p ./log/script/console && \ 8 | cp /home/dev/.tmux.conf ./.tmux.conf && \ 9 | cp /home/dev/.profile ./.profile 10 | 11 | COPY ./credentials.sh ./credentials.sh 12 | 13 | RUN . ./credentials.sh && \ 14 | /home/steam/steamcmd/steamcmd.sh \ 15 | +login $STEAMUSER $STEAMPASS \ 16 | +force_install_dir /home/steam \ 17 | +app_update 233780 validate \ 18 | +exit && \ 19 | rm -rf ./credentials.sh && \ 20 | export STEAMUSER="" && \ 21 | export STEAMPASS="" 22 | 23 | 24 | COPY ./scripts . 25 | COPY ./keys/id_rsa.pub /root/.ssh/authorized_keys 26 | COPY ./keys/id_rsa.pub /steam/.ssh/authorized_keys 27 | 28 | 29 | COPY ./configuration/ /configuration 30 | COPY ./profiles/ /profiles 31 | 32 | VOLUME ["/home/steam/mpmissions", "/home/steam/mods", "/configuration", "/profiles"] 33 | 34 | 35 | EXPOSE 2345 2344 2305 2304 2303 2302 22 36 | 37 | USER root 38 | ENTRYPOINT ["./startup"] 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arma 3 Dedicated Server Docker Setup 2 | 3 | This is a dockerfile for running an Arma 3 dedicated server. It supports mods, SSH and persistent configuration via volumes. 4 | 5 | This container has an ssh server set up and listening on container port 22. This should allow you to ssh in and do anything you may need to do inside of the container remotely without having to tear it down and start it up again. 6 | 7 | This container also ships with tmux and vim installed and some dot files that modify some tmux settings. [Take a look at the tmux.conf](https://github.com/adamveld12/laughing-hipster/blob/master/.tmux.conf) to see all of the alterations. 8 | 9 | 10 | There are a few volumes set up in this container: 11 | 12 | `/configuration`: The server.cfg and the basic.cfg files 13 | 14 | `/profiles`: The server user profile settings 15 | 16 | `/home/steam/mpmissions`: The mp missions folder 17 | 18 | `/home/steam/mods`: Mods 19 | 20 | Lastly, there is a prebuilt image available on [Docker Hub](https://registry.hub.docker.com/u/adamveld12/arma3/). 21 | 22 | 23 | ## How to use 24 | 25 | 1. [Install Docker for your system](https://docs.docker.com/installation/) 26 | 27 | For Ubuntu trusty 14.04, just do `wget -qO- https://get.docker.com/ | sh` 28 | 29 | 30 | 2. Build it from source: 31 | 32 | `./build.sh` 33 | 34 | You will get prompted to password protect the ssh key used to connect to the container after its running, and for steam account credentials so that the build can install the arma 3 dedicated server tools. 35 | 36 | *NOTE*: You should use your junk steam account, or [create one if you haven't already and start using it for your dedicated server instances.](https://developer.valvesoftware.com/wiki/SteamCMD#SteamCMD_Login) 37 | 38 | or docker pull it: 39 | 40 | `docker pull adamveld12/arma3` 41 | 42 | 3. Run it: 43 | 44 | `./run.sh` 45 | 46 | This prompts you for a name and [sets up a data container](http://container42.com/2013/12/16/persistent-volumes-with-docker-container-as-volume-pattern/) to hold your mods, mpmissions and configuration settings. Next, an arma3 server container is created and ran, using the volumes from the data container as data storage. The script links the volumes from the data container to the server, allowing you to edit configurations and mods without losing your changes. 47 | 48 | From here, you should see your game show up in the server browser after a few seconds. Make sure to edit the configuration files to your liking, they will persist between runs. 49 | 50 | You can reuse the same data and restart the server by using `./run.sh` and giving the same name for the data container. It will give you a yes/no prompt asking if you want to overwrite the old data with a new fresh configuration. 51 | 52 | 53 | After you start a new container one easy way that you can check if your server is running is by [using the server browser by BIS](http://master.bistudio.com/?page=1&count=10&game_id=6) (make sure to add your server's IP and steam query port so that the browser knows about your server) 54 | 55 | The server is ran inside of a tmux session under the steam user. The steam user has limited access to the file system and is mostly locked down to the /home/steam directory. If you would like to access the server then you can ssh in, run `su steam` and `tmux attach` to get to the running server. 56 | 57 | 58 | ## Installing missions 59 | 60 | You just need to get your missions/scenarios into the /home/steam/mpmissions volume some how, and below are a couple of ways of doing that. 61 | 62 | 1. With SSH 63 | 64 | You can SCP missions into /home/steam/mpmissions like so: 65 | 66 | `scp -i ./keys/id_rsa -p 2222 ./my_mission.Altis.pbo root@localhost:/home/steam/mpmissions/my_mission.Altis.pbo` 67 | 68 | You can also use globs to speed things up: 69 | 70 | `scp -i ./keys/id_rsa -p 2222 ./*.pbo root@localhost:/home/steam/mpmissions/` 71 | 72 | 2. Locate and copy into the volume folders 73 | 74 | Find the volumes in use by doing: 75 | 76 | `docker inspect data-arma3 | grep "var/lib/docker/*/_data"` 77 | 78 | and then copy them into the path that maps to the /home/steam/mpmissions folder. Then make sure to edit your map rotations/whitelist in the server.cfg and you should be all set. 79 | 80 | 81 | ## Installing mods 82 | 83 | To be written. 84 | 85 | 86 | ## Running multiple instances 87 | 88 | *NOTE*: I will include a guide on how to run multiple instances on one machine at a later time. 89 | 90 | 91 | ## Default Settings 92 | 93 | For the most part you get the server setup with pretty decent defaults. Verify signatures=2, battle eye enabled, and some networking tweaks in the basic.cfg to name a few. The admin RCON is disabled and so is the server password. I have taken some steps to harden the ssh server against outside intrusion, and you can see the base image used [here](https://github.com/adamveld12/ssh-server) 94 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | name="adamveld12/arma3" 5 | 6 | if [[ -f "./keys/id_rsa" && -f "./keys/id_rsa.pub" ]]; then 7 | echo "Using existing keypair..." 8 | else 9 | echo -n "Your ssh password (leave blank for no password) [ENTER]: " 10 | read -es sshpass 11 | echo 12 | 13 | echo -n "Generating key pair for SSH in ./keys..." 14 | rm -rf ./keys 15 | mkdir ./keys 16 | ssh-keygen -b 4096 -N "${sshpass}" -f ./keys/id_rsa -C "Arma 3 Admin Server Key" &> /dev/null 17 | fi 18 | 19 | if [[ ! -f ./credentials.sh ]]; then 20 | steamuser="" 21 | steampass="" 22 | echo -n "Steam account username? [ENTER]: " 23 | read -e steamuser 24 | echo 25 | 26 | echo -n "Steam account password? [ENTER]: " 27 | read -s steampass 28 | echo 29 | 30 | echo -e "#!/bin/bash\nexport STEAMUSER=\"${steamuser}\"\nexport STEAMPASS=\"${steampass}\"" > ./credentials.sh 31 | chmod +x ./credentials.sh 32 | fi 33 | 34 | echo -e "Building container as \"${name}\"..." 35 | docker build -t ${name} . 36 | 37 | if [[ -f $(which boot2docker) ]]; then 38 | IP=$(boot2docker ip) 39 | else 40 | IP=127.0.0.1 41 | fi 42 | 43 | echo "${name} completed." 44 | echo "to ssh into your container:" 45 | echo "ssh root@${IP} -i ./keys/id_rsa -p 2222" 46 | 47 | -------------------------------------------------------------------------------- /configuration/basic.cfg: -------------------------------------------------------------------------------- 1 | // basic.cfg - Defines network tuning parameters 2 | // 3 | // This file is to be passed to the -cfg parameter on the command line for the server 4 | // See http://community.bistudio.com/wiki/basic.cfg 5 | // The following settings are the suggested settings 6 | 7 | // GEOLOCATION SETTINGS 8 | 9 | // Server latitude 10 | serverLatitude=52; 11 | serverLatitudeAuto=52; 12 | 13 | // Server Longitude 14 | serverLongitude=0; 15 | serverLongitudeAuto=0; 16 | 17 | // BANDWIDTH SETTINGS 18 | 19 | // Bandwidth the server is guaranteed to have (in bps) 20 | // General guideline is NumberOfPlayers * 256kb 21 | MinBandwidth=5120000; // Default: 131072 22 | 23 | // Bandwidth the server can never go above (in bps) 24 | // For a single server, use full network speed; decrease when running multiple servers 25 | MaxBandwidth=10240000; 26 | 27 | // PACKET SETTINGS 28 | 29 | // Maximum number of packets per frame. 30 | // Increasing the value potentially decreases lag, but increases desync 31 | MaxMsgSend=2048; // Default: 128 32 | 33 | // Maximum payload of guaranteed packet (in b) 34 | // Small messages are packed to larger packets 35 | // Guaranteed packets are used for non-repetitive events, like shooting 36 | // Lower value means more packets are sent, so less events will get combined 37 | MaxSizeGuaranteed=512; // Default: 512 38 | 39 | // Maximum payload of non-guaranteed packet (in b) 40 | // Increasing this value may improve bandwidth requirement, but may also increase lag 41 | // Largest factor in desync 42 | // Guidance is half of MaxSizeGuaranteed 43 | MaxSizeNonguaranteed=256; // Default: 256 44 | 45 | // Maximal size of a packet sent over the network 46 | // Only necessary if ISP forces lower packet size and there are connectivity issues 47 | // Default: 1400 48 | // class sockets{maxPacketSize=1400}; 49 | 50 | // SMOOTHNESS SETTINGS 51 | 52 | // Minimal error required to send network updates for far units 53 | // Smaller values will make for smoother movement at long ranges, but will increase network traffic 54 | MinErrorToSend=0.01; // Default: 0.003 55 | 56 | // Minimal error required to send network updates for near units 57 | // Using larger value can reduce traffic sent for near units 58 | // Also controls client to server traffic 59 | MinErrorToSendNear=0.02; // Default: 0.01 60 | 61 | 62 | // MISC 63 | 64 | // View Distance (not sure if this actually works) 65 | viewDistance=10000; 66 | 67 | // Maximum size (in b) for custom face or sound files 68 | MaxCustomFileSize=0; 69 | 70 | // Server language 71 | language="English"; 72 | steamLanguage="English"; 73 | 74 | adapter=-1; 75 | Windowed=0; 76 | 3D_Performance=1.000000; 77 | -------------------------------------------------------------------------------- /configuration/server.cfg: -------------------------------------------------------------------------------- 1 | // server.cfg 2 | // ArmA 3 Server Config File 3 | // NOTE: More parameters and details are available at http://community.bistudio.com/wiki/server.cfg 4 | 5 | // Networking 6 | 7 | serverport = 2302; //default: 2302. 8 | upnp = 1; // Automatically creates port mapping on UPNP/IGD enabled router. 9 | 10 | headlessClients[] = {}; // list of IP addresses allowed to connect using headless clients; example: {"127.0.0.1", "192.168.1.100"}; 11 | localClient[] = {}; // list of IP addresses to which are granted unlimited bandwidth; example: {"127.0.0.1", "192.168.1.100"}; 12 | 13 | // GENERAL SETTINGS 14 | 15 | hostname = "My Docker Arma 3 Server"; // Name of the server displayed in the public server list 16 | //password = "ServerPassword"; // Password required to join the server (remove // at start of line to enable) 17 | //passwordAdmin = "AdminPassword"; // Password to login as admin. Open the chat and type: #login password 18 | maxPlayers = 32; // Maximum amount of players, including headless clients. Anybody who joins the server is considered a player, regardless of their role or team. 19 | persistent = 1; // If set to 1, missions will continue to run after all players have disconnected; required if you want to use the -autoInit startup parameter 20 | forceRotorLibSimulation = 0; // Enforces the Advanced Flight Model on the server. Default = 0 (up to the player). 1 - forced AFM, 2 - forced SFM. 21 | 22 | motdInterval = 5; // Number of seconds between each message 23 | 24 | // WELCOME MESSAGE ("message of the day") 25 | // It can be several lines, separated by comma 26 | // Empty messages "" will not be displayed, but can be used to increase the delay before other messages 27 | motd[] = { 28 | "Welcome to my Arma 3 server", 29 | "This server is powered by Docker", 30 | "https://github.com/adamveld12/arma3server" 31 | }; 32 | 33 | 34 | // LOGGING 35 | 36 | timeStampFormat = "full"; // Timestamp format used in the server RPT logs. Possible values are "none" (default), "short", "full" 37 | logFile = "/configuration/server_console.log"; // Server console output filename 38 | 39 | // VOICE CHAT 40 | 41 | disableVoN = 0; // If set to 1, voice chat will be disabled 42 | vonCodecQuality = 10; // Supports range 1-30; 1-10 is 8kHz (narrowband), 11-20 is 16kHz (wideband), 21-30 is 32kHz (ultrawideband); higher = better sound quality, more bandwidth consumption 43 | 44 | // VOTING 45 | 46 | voteMissionPlayers = 1; // Minimum number of players required before displaying the mission selection screen, if you have not already selected a mission in this config 47 | voteThreshold = 0.33; // Percentage (0.00 to 1.00) of players needed to vote something into effect, for example an admin or a new mission. Set to 9999 to disable voting. 48 | 49 | allowedVoteCmds[] = // Voting commands allowed to players 50 | { 51 | // {command, preinit, postinit, threshold} - specifying a threshold value will override "voteThreshold" for that command 52 | {"admin", false, false}, // vote admin 53 | {"kick", false, true, 0.51}, // vote kick 54 | {"missions", false, false}, // mission change 55 | {"mission", false, false}, // mission selection 56 | {"restart", false, false}, // mission restart 57 | {"reassign", false, false} // mission restart with roles unassignedG 58 | }; 59 | 60 | allowedVotedAdminCmds[] = { // Definition of available commands for voted-in admins (this doesn't affect abilities of normal server admins) 61 | // {"mission", true, true}, 62 | // {"missions", true, true}, 63 | // {"restart", true, true}, 64 | // {"reassign", true, true}, 65 | // {"kick", true, true} 66 | }; 67 | 68 | // MISSIONS CYCLE 69 | 70 | class Missions {}; // An empty Missions class means there will be no mission rotation 71 | missionWhitelist[] = {}; // An empty whitelist means there is no restriction on what missions' available 72 | 73 | 74 | 75 | // SECURITY 76 | BattlEye = 1; // If set to 1, BattlEye Anti-Cheat will be enabled on the server (default: 1, recommended: 1) 77 | verifySignatures = 2; // If set to 2, players with unknown or unsigned mods won't be allowed join (default: 0, recommended: 2) 78 | kickDuplicate = 1; // If set to 1, players with an ID that is identical to another player will be kicked (recommended: 1) 79 | 80 | // FILE EXTENSIONS 81 | allowedLoadFileExtensions[] = {"hpp","sqs","sqf","fsm","cpp","paa","txt","xml","inc","ext","sqm","ods","fxy","lip","csv","kb","bik","bikb","html","htm","biedi"}; // only allow files with those extensions to be loaded via loadFile command (since Arma 3 v1.19.124216) 82 | allowedPreprocessFileExtensions[] = {"hpp","sqs","sqf","fsm","cpp","paa","txt","xml","inc","ext","sqm","ods","fxy","lip","csv","kb","bik","bikb","html","htm","biedi"}; // only allow files with those extensions to be loaded via preprocessFile/preprocessFileLineNumber commands (since Arma 3 v1.19.124323) 83 | allowedHTMLLoadExtensions[] = {"htm","html","xml","txt"}; // only allow files with those extensions to be loaded via HTMLLoad command (since Arma 3 v1.27.126715) 84 | 85 | // EVENT SCRIPTS - see http://community.bistudio.com/wiki/ArmA:_Server_Side_Scripting 86 | onUserConnected = ""; // command to run when a player connects 87 | onUserDisconnected = ""; // command to run when a player disconnects 88 | doubleIdDetected = ""; // command to run if a player has the same ID as another player in the server 89 | onUnsignedData = "kick (_this select 0)"; // command to run if a player has unsigned files 90 | onHackedData = "ban (_this select 0)"; // command to run if a player has tampered files 91 | -------------------------------------------------------------------------------- /debug.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker run -it \ 3 | -p 2302-2305:2302-2305/udp \ 4 | -p 2344-2345:2344-2345/udp -p 2344-2345:2344-2345/tcp \ 5 | -p 8766:8766/udp -p 27016:27016/udp \ 6 | -p 2222:22 \ 7 | -v $PWD/configuration:/configuration \ 8 | -v $PWD/profiles:/profiles \ 9 | adamveld12/arma3 10 | /bin/bash 11 | -------------------------------------------------------------------------------- /profiles/home/server/server.Arma3Profile: -------------------------------------------------------------------------------- 1 | version=2; 2 | 3 | viewDistance=3000; 4 | preferredObjectViewDistance=3000; 5 | terrainGrid=12.5; 6 | activeKeys[]= 7 | { 8 | }; 9 | 10 | 11 | class Difficulties 12 | { 13 | class recruit 14 | { 15 | class Flags 16 | { 17 | Armor=1; 18 | FriendlyTag=0; 19 | EnemyTag=0; 20 | MineTag=1; 21 | HUD=1; 22 | HUDPerm=1; 23 | HUDWp=1; 24 | HUDWpPerm=1; 25 | HUDGroupInfo=1; 26 | AutoSpot=1; 27 | Map=1; 28 | WeaponCursor=1; 29 | AutoGuideAT=1; 30 | ClockIndicator=1; 31 | 3rdPersonView=1; 32 | UltraAI=0; 33 | CameraShake=0; 34 | UnlimitedSaves=1; 35 | DeathMessages=1; 36 | NetStats=1; 37 | VonID=1; 38 | ExtendedInfoType=1; 39 | }; 40 | skillFriendly=0.6; 41 | skillEnemy=0.6; 42 | precisionFriendly=0.28; 43 | precisionEnemy=0.28; 44 | }; 45 | class regular 46 | { 47 | class Flags 48 | { 49 | Armor=1; 50 | FriendlyTag=1; 51 | EnemyTag=0; 52 | MineTag=1; 53 | HUD=1; 54 | HUDPerm=1; 55 | HUDWp=1; 56 | HUDWpPerm=1; 57 | HUDGroupInfo=1; 58 | AutoSpot=1; 59 | Map=1; 60 | WeaponCursor=1; 61 | AutoGuideAT=1; 62 | ClockIndicator=1; 63 | 3rdPersonView=1; 64 | UltraAI=0; 65 | CameraShake=1; 66 | UnlimitedSaves=1; 67 | DeathMessages=1; 68 | NetStats=1; 69 | VonID=1; 70 | ExtendedInfoType=1; 71 | }; 72 | skillFriendly=0.6; 73 | skillEnemy=0.6; 74 | precisionFriendly=0.28; 75 | precisionEnemy=0.28; 76 | }; 77 | class veteran 78 | { 79 | class Flags 80 | { 81 | Armor=0; 82 | FriendlyTag=0; 83 | EnemyTag=0; 84 | MineTag=1; 85 | HUD=1; 86 | HUDWp=1; 87 | HUDWpPerm=1; 88 | HUDGroupInfo=1; 89 | AutoSpot=0; 90 | WeaponCursor=0; 91 | ClockIndicator=1; 92 | 3rdPersonView=1; 93 | UltraAI=0; 94 | CameraShake=0; 95 | DeathMessages=0; 96 | NetStats=1; 97 | VonID=1; 98 | ExtendedInfoType=0; 99 | }; 100 | skillFriendly=0.6; 101 | skillEnemy=0.6; 102 | precisionFriendly=0.28; 103 | precisionEnemy=0.28; 104 | }; 105 | class mercenary 106 | { 107 | class Flags 108 | { 109 | HUD=1; 110 | AutoSpot=0; 111 | WeaponCursor=0; 112 | DeathMessages=0; 113 | NetStats=1; 114 | VonID=1; 115 | }; 116 | skillFriendly=0.6; 117 | skillEnemy=0.6; 118 | precisionFriendly=0.28; 119 | precisionEnemy=0.28; 120 | }; 121 | }; 122 | 123 | difficulty="veteran"; 124 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | dataAlias="data-arma3" 5 | echo -n "data container name [defaults to data-arma3]:" 6 | read dataAlias 7 | 8 | 9 | if [[ $dataAlias == "" ]]; then 10 | dataAlias="data-arma3" 11 | fi 12 | 13 | if [[ ! -z $(docker ps -a | grep "$dataAlias") ]]; then 14 | answer="" 15 | echo "Would you like to overwrite the existing data container of the same name [y for yes, or anything for no] " 16 | read answer 17 | if [[ $answer == "y" ]]; then 18 | docker rm $dataAlias 19 | else 20 | exit 21 | fi 22 | fi 23 | 24 | docker run -d \ 25 | -v /configuration \ 26 | -v /profiles \ 27 | -v /home/steam/mpmissions \ 28 | -v /home/steam/mods \ 29 | --name $dataAlias --entrypoint /bin/echo \ 30 | adamveld12/arma3 \ 31 | "Arma 3 data-only container" 32 | 33 | if [[ -z $(docker ps | grep "adamveld12/arma3") ]]; then 34 | docker run -td \ 35 | -p 2302-2305:2302-2305/udp \ 36 | -p 2344-2345:2344-2345/udp -p 2344-2345:2344-2345/tcp \ 37 | -p 8766:8766/udp -p 27016:27016/udp \ 38 | -p 2222:22 \ 39 | --volumes-from $dataAlias \ 40 | adamveld12/arma3 41 | else 42 | echo "server container already running" 43 | fi 44 | -------------------------------------------------------------------------------- /scripts/startserver: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ./arma3server -netlog -profiles=/profiles -name=server -cfg=/configuration/basic.cfg -config=/configuration/server.cfg -mod= 3 | -------------------------------------------------------------------------------- /scripts/startup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd /home/steam 3 | su -c "tmux new-session -d -s \"Arma 3 Server\" -n \"Arma 3 Dedicated Server Instance\" /home/steam/startserver" steam 4 | /usr/sbin/sshd -D 5 | --------------------------------------------------------------------------------