Need help with Gamocosm?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

Gamocosm
155 Stars 24 Forks GNU General Public License v2.0 389 Commits 30 Opened issues

Description

Honest Minecraft server hosting

Services available

!
?

Need anything else?

Contributors list

Gamocosm Build Status Coverage Status Gitter chat

Gamocosm makes it easy to run cloud Minecraft servers. Digital Ocean is used as the backend/hosting service, due to cost, reliability, and accessibility. Gamocosm works well for friends who play together, but not 24/7. Running a server 14 hours a week (2 hours every day) may cost 40 cents a month, instead of $5.

Minecraft Server Wrapper

The Minecraft Server Wrapper (for lack of a better name) is a light python webserver. It provides an HTTP API for starting and stopping Minecraft servers, downloading the world, etc. Please check it out and help improve it too!

Gamocosm Minecraft Flavours

The gamocosm-minecraft-flavours repository includes the setup scripts used to install different flavours of Minecraft on a new server. Read this wiki page for adding support for new flavours, or manually installing something yourself.

Contributing

Pull requests are welcome!

Setting up your development environment

You should have a Unix/Linux system. The following instructions were made for Fedora 31, but the steps should be similar on other distributions.

  1. Install postgresql and development headers and libraries, memcached, redis, and nodejs:
    (sudo) dnf install postgresql-server postgresql-contrib postgresql-devel memcached redis nodejs
  2. Install rbenv and ruby-build. Read the instructions on their page (will be up to date)
  3. Install dependencies to build ruby:
    (sudo) dnf install gcc gcc-c++ openssl-devel readline-devel zlib-devel
  4. Install Ruby 2.6.5:
    rbenv install 2.6.5
    .
  5. Check that
    ruby -v
    inside your cloned
    gamocosm
    folder gives you version 2.6.5
  6. Install Bundler:
    gem install bundler
  7. Install gem dependencies:
    bundle install
  8. Run
    cp env.sh.template env.sh
  9. Enter config in
    env.sh
  10. Initialize postgresql:
    (sudo) postgresql-setup initdb --unit postgresql
  11. Configure the database (explained below)
  12. Start postgresql, memcached, and redis manually:
    (sudo) systemctl start 
    , or enable them to start at boot time:
    (sudo) systemctl enable 
  13. Run
    ./sysadmin/run.sh bundle exec rake db:setup
  14. Start the server:
    ./sysadmin/run.sh bundle exec rails s
  15. Start the Sidekiq worker:
    ./sysadmin/run.sh bundle exec sidekiq

Directory hierarchy

  • app
    : main source code
  • bin
    : rails stuff, don't touch
  • config
    : rails app configuration
  • db
    : rails app database stuff (schema, migrations, seeds)
  • lib
    : rails stuff, don't touch
  • log
    : 'nuff said
  • public
    : static files
  • sysadmin
    : stuff for the Gamocosm server (you can run your own server! This is a true open source project)
  • test-docker
    : use docker container to test most of
    app/workers/setup_server_worker.rb
    (more below)
  • test
    : pooteeweet
  • vendor
    : rails stuff, don't touch

env.sh options

The script

./sysadmin/run.sh
basically sources
env.sh
then
exec
s the supplied command. You can
source env.sh
to load the relevant environment variables into your shell yourself. Then you can run stuff like
bundle exec ...
directly.
  • DIGITAL_OCEAN_API_KEY
    : your Digital Ocean api token
  • DIGITAL_OCEAN_SSH_PUBLIC_KEY_PATH
    : ssh key to be added to new servers to SSH into
  • DIGITAL_OCEAN_SSH_PRIVATE_KEY_PATH
    : see above
  • DIGITAL_OCEAN_SSH_PRIVATE_KEY_PASSPHRASE
    : see above
  • SIDEKIQ_ADMIN_USERNAME
    : HTTP basic auth for Sidekiq web interface
  • SIDEKIQ_ADMIN_PASSWORD
    : see above
  • DATABASE_USER
    : hmmmm
  • DATABASE_PASSWORD
    : hmmmm
  • DATABASE_HOST
    : database host. If specified, Rails will use a TCP connection (e.g. "localhost"). If left blank, Rails will use a local Unix socket connection
  • MAIL_SERVER_*
    : see action mailer configuration in the Rails guide
  • USER_SERVERS_DOMAIN
    : subdomain for user servers (e.g.
    gamocosm.com
    )
  • CLOUDFLARE_API_TOKEN
    : hmmm
  • CLOUDFLARE_EMAIL
    : hmmm
  • CLOUDFLARE_ZONE
    : shown on the bottom right of CloudFlare's control panel for the domain
  • DEVELOPMENT_HOST
    : only development, allowed host to access development server
  • DEVISE_SECRET_KEY
    : only test, production
  • SECRET_KEY
    : only production
  • DEVELOPER_EMAILS
    : comma separated list of emails to send exceptions to
  • BADNESS_SECRET
    : secret to protect
    /badness
    endpoint

Database configuration

Locate

pg_hba.conf
. On Fedora this is in
/var/lib/pgsql/data/
. This file tells postgresql how to authenticate users. Read about it on the PostgreSQL docs. To restart postgresql:
(sudo) service postgresql restart
config/database.yml
gets the database username from the environment variable
DATABASE_USER
(default "gamocosm"). The default value in "env.sh.template" for
DATABASE_HOST
is blank, so if you don't change it Rails will use a local Unix socket connection. The postgres user you use must be a postgres superuser, as rails needs to enable the uuid extension. To create a postgres user "gamocosm":
  • Switch to the
    postgres
    user:
    (sudo) su - postgres
  • Run
    createuser --createdb --pwprompt --superuser gamocosm
    (
    createuser --help
    for more info)

Depending on what method you want to use, add the following under the line that looks like

# TYPE DATABASE USER ADDRESS METHOD
.
  • Type
    • local
      (local Unix socket) or
      host
      (TCP connection)
  • Database
    • Rails also needs to have access to the
      postgres
      database (to create new databases?)
    • postgres,gamocosm_development,gamocosm_test,gamocosm_production
  • User
    • gamocosm
  • Address
    • Leave blank for
      local
      type
    • Localhost is
      127.0.0.1/32
      in ipv4 and
      ::1/128
      in ipv6. My system used ipv6 (postgres did not match the entry when I entered localhost ipv4)
  • Method
    • trust
      • Easiest, but least secure. Typically ok on development machines. Blindly trusts the user
    • peer
      • Checks if the postgresql user matches the operating system user
      • Since
        config/database.yml
        specifies the database user to be "gamocosm", using this method is more troublesome, at least in development, because you have to either change that to your OS username and create a postgresql user with your username, or create a new OS account called "gamocosm" and a postgresql user "gamocosm"
    • ident
      • Same as
        peer
        but for network connections
    • md5
      • Client supplies an MD5-encrypted password
      • This is the recommended method

Example:

local postgres,gamocosm_development,gamocosm_test,gamocosm_production gamocosm md5

Technical details

Hmmmm.

Data

  • Gamocosm has a lot of infrastructure:
    • CloudFlare DNS API
    • Digital Ocean API
    • Digital Ocean servers/droplets
    • Minecraft and the server wrapper
    • Gamocosm Rails server
    • Gamocosm Sidekiq background workers
  • Avoid state and duplicating data (less chance of corruption, logic easier to debug than data)
  • Idempotency is good

Error handling

  • Methods that "do things" should return nil on success, or an object on error
  • Methods that "return things" should use
    String#error!
    to mark a return value is an error
    • This method takes 1 argument: a data object (can be
      nil
      )
    • e.g.
      'API response code not 200'.error!(res)
    • String#error!
      returns an
      Error
      object;
      Error#to_s
      is overridden so the error message can be shown to the user, or the error data (
      Error#data
      ) can be further inspected for handling
  • You can use
    .error?
    to check if a return value is an error.
    Error#error?
    is overriden to return
    true
  • This class and these methods are defined in
    config/initializers/monkey_patches.rb
  • Throw exceptions in "exceptional cases", when something is unexpected (e.g. bad user input is expected) or can't be handled without "blowing up"

Important checks

  • server.remote.exists?
    :
    !server.remote_id.nil?
  • server.remote.error?
    : whether there was an error or not retrieving info about a droplet from Digital Ocean
    • true if the user is missing his Digital Ocean API token, or if it's invalid
    • false if
      !server.remote.exists?
    • don't need to check this before
      server.remote
      actions (e.g.
      server.remote.create
      )
  • server.running?
    :
    server.remote.exists? && !server.remote.error? && server.remote.status == 'active'
  • user.digital_ocean.nil?
    : Digital Ocean API token missing
  • minecraft.node.error?
    : error communicating with Minecraft wrapper on server
  • minecraft.running?
    :
    server.running? && !node.error? && node.pid > 0
    (notice symmetry with
    server.running?
    )

Background workers

  • Idempotent
  • Keep blocks inside timeouts as simple as possible, cleanup outside of timeout, try to stick to plain old datatypes
    • Use
      ActiveRecord::Base.connection_pool.with_connection do |conn|
      if threads (e.g. timeout) access the database
  • Run finite amount of times (keep track of how many times looped)
  • Reset the state of the server if anything goes wrong (any exit points)
  • Check that the remote exists and is not errored
  • Log errors to user minecraft server, include 'Aborting' when not finishing
  • 'Aborting' should always be followed by
    server.reset_state
    and
    return

Other useful stuff

  • Development/test user (from
    db/seed.rb
    ): email "[email protected]", password "1234test", has the Digital Ocean api token from
    env.sh
    • the current tests don't use this, and mock all HTTP requests/responses
  • The Sidekiq web interface is mounted at
    /sidekiq
  • Sidekiq doesn't automatically reload source files when you edit them. You must restart it for changes to take effect
  • New Relic RPM is available in developer mode at
    /newrelic
  • Run the console:
    bundle exec rails c
  • Reset the database:
    bundle exec rake db:reset
  • Reset Sidekiq jobs:
    Sidekiq::Queue.new.each { |job| job.delete }
    in the rails console
  • Reset Sidekiq stats:
    Sidekiq::Stats.new.reset
    in the rails console
  • The deployment scripts and configuration are in the
    sysadmin/
    directory
  • List of
    rake db
    commands: Stack Overflow

Tests

  • bundle exec rails test
    or
    ./tests.sh
  • tests use WebMock to mock http requests (no external requests)
  • RAILS_ENV=test bundle exec rails 
    to run the server or console (respectively) in test mode
  • Note: the test server, unlike the dev server, does not automatically reload source files when you change them

More testing by simulating a user server with Docker

Without a server to connect to, Gamocosm can't try SetupServerWorker or AutoshutdownMinecraftWorker. "test-docker/" contains a Dockerfile for building a basic Fedora container with an SSH server (simulating a bare Digital Ocean server). If you set

$TEST_DOCKER
to "true", the tests will assume there is a running Docker Gamocosm container to connect to.

tests.sh
will build the image, start the container, and delete the container for you if you specify to use Docker. Otherwise, it will run the tests normally (equivalent to
bundle exec rails test
). You should have non-root access to Docker. You could also manage Docker yourself; you can look at the
tests.sh
file for reference.

Example:

TEST_DOCKER=true ./tests.sh

Credits

  • Special thanks to geetfun who helped with the original development
  • Special thanks to binary-koan (Jono Mingard) for designing the new theme! Looks awesome!
  • SuperMarioBro for helping iron out some initial bugs, adding support for more Minecraft flavours
  • bearbin for helping iron out some initial bugs
  • chiisana for feedback and other ideas, resources
  • KayoticSully for planning and development on the server wrapper API
  • Jadorel for feedback and helping iron out some bugs
  • Ajusa for helping with some bugs

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.