Getting Started¶
Installing the Scoreboard¶
As a Python WSGI application, it can be run in any environment that supports the WSGI protocol.
Warning
Irrespectable of which way you choose, you must make sure that the
complete /admin
path is protected by external measures (e.g. HTTP
Basic Auth). The backend has no separate protection.
Warning
If not using Nginx, you have to make sure to manually set the Host
header to a static value and not trust the client as Pyramid relies on it
to generate URLs!
Quickstart¶
First of all: The scoreboard uses PostgreSQL (and has only been tested with it). It does explicitly not support MySQL as MySQL is crappy software. However, it does not rely on obscure database features so you may get it running with a different server (though not MySQL. Never MySQL.). So go ahead and install PostgreSQL. You can then prepare the database:
-- Choose a secure password here!
CREATE USER fluxscoreboard WITH PASSWORD 'mypass';
CREATE DATABASE scoreboard WITH OWNER fluxscoreboard;
Now let’s install! Adjust the paths to your liking. Also pay attention to the username and group for the web server, it depends on the server you are using and the distribution, it may for example be “www-data” or “http” or “www”. You should also use virtualenv instead of your global python installation to run the scoreboard under.
mkdir -p /var/www/ctf
cd /var/www/ctf
chown http:http .
virtualenv .
. bin/activate
git clone git@github.com:Javex/fluxscoreboard.git
cd fluxscoreboard/
./run install production
Now create a valid configuration by opening cfg/production.ini
and
filling in all relevant values (everything is documented there). The run
tool
has already performed some of the heavy lifting.
Webserver Nginx + gunicorn¶
This is an example configuration file that can be used with Nginx. For this server you additionally need a reverse proxy that handles the WSGI protocol.
upstream fluxscoreboard {
server 127.0.0.1:6875;
}
server {
listen 80;
server_name mydomain.com;
rewrite ^ https://$server_name$request_uri? permanent; # enforce https
}
server {
listen 443 ssl;
server_name mydomain.com;
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private_key.key;
access_log /var/log/nginx/fluxscoreboard_access.log;
error_log /var/log/nginx/fluxscoreboard_error.log;
# This is not needed if the page itself should be public
#auth_basic "Restricted";
#auth_basic_user_file /var/www/ctf/fluxscoreboard/.htpasswd;
# Security headers
add_header X-Frame-Options DENY;
add_header Content-Security-Policy "default-src 'none'; connect-src 'self'; font-src 'self'; img-src 'self' www.google.com; script-src 'self' www.google.com 'sha256-dtX3Yk6nskFEtsDm1THZkJ4mIIohKJf5grz4nY6HxI8='; style-src 'self';";
add_header X-XSS-Protection 0;
add_header Strict-Transport-Security max-age=31536000;
location / {
# This file must be available under a sensible name and is reference
# relative to /etc/nginx (or wherever nginx.conf lies)
include nginx_proxy.conf;
}
location /admin {
# This file must be available under a sensible name and is reference
# relative to /etc/nginx (or wherever nginx.conf lies)
include nginx_proxy.conf;
# This MUST be active to protect the admin backend. It may NOT be
# deactivated as it exposes a lot of features including adding a lot of
# data and sending emails.
auth_basic "Restricted";
auth_basic_user_file /var/www/ctf/fluxscoreboard/.htpasswd_admin;
}
location /static {
# A path to the root, i.e. it will have /static appended (+ the
# searched file). This circumvents the application server as these are
# static anyway.
root /var/www/ctf/fluxscoreboard/fluxscoreboard;
expires 30d;
add_header Cache-Control public;
access_log off;
}
}
This defines the base application. It is configured for SSL only access and automatically redirects any HTTP requests. There is not much to change here except that you might want a different path for your application. However, there is a second file that contains the actual options:
# Don't trust the client on this one!
proxy_set_header Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
# This is set to assure the Client-Addr is trustworthy
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 60s;
proxy_send_timeout 90s;
proxy_read_timeout 90s;
proxy_buffering off;
proxy_temp_file_write_size 64k;
proxy_redirect off;
proxy_pass http://fluxscoreboard;
This file has to be saved somewhere as-is and the path in the main configuration has to be adjusted in such a way that it points to it relative to the Nginx main configuration directory (see comments in file). Restart Nginx.
Note
The sample configuration sets the ‘Host’ header statically to whatever
server_name
setting you chose. Do not trust the $host
header of
the client: It may be spoofed but Pyramid relies on it so we have to make
sure it is a trusted value!
After Nginx is configured this way you don’t have to do much for gunicorn: It already has a valid configuration in the default configuration file (see below).
Todo
Configure gunicorn with proper logging.
Protecting the Admin Backend¶
Finally, you should protect your backend with HTTP Auth:
htpasswd -c -b /var/www/ctf/fluxscoreboard/.htpasswd_admin fluxadmin secretpassword
This will protect your backend from unauthorized access.
Cron!¶
Since calculating points is a heavy task, you should not do it on every request from a user. Instead, we provide a convenience function that regularly updates the points of teams and challenges:
./run update_points
Make sure to put that in a cron. Run it e.g. every five minutes.
Test it!¶
This should be it. You should start the server as a test:
gunicorn_paster production.ini
Try out the server by visiting the domain configured for Nginx. Fix any errors
that appear, then enable the daemon = True
option for gunicorn in
production.ini
. You are now good to go. A simple setup is to just run it
and close the shell. However, with this way you have no service, no monitoring
and no restarting.
Todo
Add some more details here.