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.
This README is directed towards developers; if you are a user looking for more information, please check out the wiki or drop by Gitter chat.
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 35, but the steps should be similar on other distributions.
Check that ruby -v inside this project gives you version 3.0.3.
Install Bundler: gem install bundler.
Install dependencies to build gems: (sudo) dnf install libpq-devel.
Install gem dependencies: bundle install.
Install postgresql and redis: (sudo) dnf install postgresql-server postgresql-contrib redis.
Initialize postgresql: (sudo) postgresql-setup --initdb (Fedora docs; note that --unit postgresql is unecessary - it is the default - see man postgresql-setup).
Configure the database; see below.
Start postgresql and redis: (sudo) systemctl start <postgresql/redis>, and optionally enable them to start at boot time: (sudo) systemctl enable <postgresql/redis>.
Generate or link your SSH keys; Gamocosm expects an id_gamocosm private key and an id_gamocosm.pub public key in the project root. Gamocosm uses this to connect to and set up the servers it creates. Gamocosm officially only supports ed25519 keys; somewhere down the stack, rsa keys are not supported (ed25519 keys are considered more secure):
To generate new keys, run: ssh-keygen -t ed25519. The default path saves to ~/.ssh/id_ed25519. If you leave it here, SSH will automatically try this key when SSHing (e.g. if you need to debug a Digital Ocean droplet created by your Gamocosm). Careful not to overwrite if you already have an existing ~/.ssh/id_ed25519 key!
To link a key ~/.ssh/id_ed25519, run ln -s ~/.ssh/id_ed25519 id_gamocosm, and similarly for the corresponding public key (with .pub extension).
If you plan on running Gamocosm in a container, note that podman/docker cannot copy symlinks; use cp to copy the files instead.
id_gamocosm and id_gamocosm.pub are ignored in Gamocosm's .gitignore so you don't have to worry about accidentally committing them.
Create your environment file: cp template.env gamocosm.env.
Make your environment file only readable (and writable) by the file owner (you): chown 600 gamocosm.env
Update the config in gamocosm.env. See below for documentation.
Load environment variables: source load_env.sh. You will need to do this in every new shell you run ruby/rails in.
Setup the database: bundle exec rails db:setup.
Start the server: bundle exec rails s.
Start the Sidekiq worker: bundle exec sidekiq.
Optional: open the console: bundle exec rails c.
Environment File
DATABASE_HOST: May be a directory (for a Unix domain socket), or an IP/hostname (for a TCP connection). The default should work on Fedora provided you didn't change the postgresql settings. See bwlo for more information.
DATABASE_PORT: Required even for Unix domain sockets. The default should work on Fedora provided you didn't change the postgresql settings.
DATABASE_USER: Hmmmm.
DATABASE_PASSWORD: Hmmmm.
DIGITAL_OCEAN_API_KEY: Your Digital Ocean API token.
DIGITAL_OCEAN_SSH_PRIVATE_KEY_PASSPHRASE: You should have generated or linked an id_gamocosm SSH key in the project root, with an (optional) passphrase.
SIDEKIQ_REDIS_HOST: You can leave this as the default.
SIDEKIQ_REDIS_PORT: You can leave this as the default.
SIDEKIQ_ADMIN_USERNAME: HTTP basic auth for Sidekiq web interface.
SIDEKIQ_ADMIN_PASSWORD: See previous.
CLOUDFLARE_API_TOKEN: Hmmm.
CLOUDFLARE_EMAIL: Hmmm.
CLOUDFLARE_ZONE: Shown on the bottom right of CloudFlare's control panel for the domain.
CACHE_REDIS_HOST: Caching for production. Is disabled/not used in development and test environments (see config/environments/development.rb and config/environments/test.rb).
CACHE_REDIS_PORT: See previous.
SECRET_KEY_BASE: Only production.
DEVELOPER_EMAILS: Comma separated list of emails to send exceptions to.
BADNESS_SECRET: Secret to protect /badness endpoint.
Database configuration
Locate your postgres data directory.
On Fedora this is /var/lib/pgsql/data/.
Connection
Locate postgresql.conf in your postgres data directory.
The convention is that commented out settings represent the default values.
For a Unix domain socket connection, DATABASE_HOST should be one of the values of unix_socket_directories.
In general, the default is /tmp.
On Fedora, the default includes both /tmp and /var/run/postgresql.
For a TCP connection, DATABASE_HOST should be one of the values of listen_addresses (default localhost).
The value localhost should work if you're running postgresql locally.
Your DATABASE_PORT should be the value of port in this file (default 5432).
You can read more about connecting to postgresql at postgresql's docs.
Authentication
Locate pg_hba.conf in your postgres data directory.
This file tells postgresql how to authenticate users. Read about it on the PostgreSQL docs.
The Rails config config/database.yml reads from the environment variables which you should have set in and loaded from gamocosm.env via source load_env.sh.
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 --login postgres.
Run createuser --createdb --pwprompt --superuser gamocosm (createuser --help for more info).
Depending on what method you want to use, in pg_hba.conf add the following under the line that looks like # TYPE DATABASE USER ADDRESS METHOD.
Type
local (Unix domain socket) or host (TCP connection)
Database
Rails also needs to have access to the postgres database (to create new databases?)
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.
You will have to restart postgresql ((sudo) systemctl restart postgresql) for the changes to take effect.
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
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)
tests use WebMock to mock http requests (no external requests)
RAILS_ENV=test bundle exec rails <s|c> 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
请发表评论