Quick answer: Rent a $10/month VPS, install nginx with a Let’s Encrypt certificate, protect download paths with basic auth, and automate build uploads from your CI. Total monthly cost $10–50 for a fully private QA pipeline with nightly builds, bug collection, and optional multiplayer testing.

Shipping pre-release builds through Discord attachments is fine until your beta group has 50 people and someone leaks a build. A private QA server gives your team and trusted testers a single place to download builds, file reports, and coordinate testing — without leaking anything to the public. It is cheaper than most people think and takes an afternoon to set up.

What You Actually Need

A QA server is not a full infrastructure rebuild. It is three things:

  1. A place to host build artifacts. Static file hosting with auth.
  2. A place to collect bug reports. Either an integration with a bug tracker (Bugnet, Jira, GitHub Issues) or a simple form that emails you.
  3. Optional: a multiplayer test backend. For games that need it.

Skip anything you do not need. A platformer has no multiplayer requirements and does not need a test server. A racing game does.

Step 1: Provision a VPS

Pick a $5–10/month VPS from:

Pick Ubuntu 22.04 LTS or newer. 1 GB RAM is enough for build hosting; bump to 2 GB if you also run a bug tracker. Install with SSH key auth only — no password logins — and configure UFW to allow only ports 22 (SSH), 80 (HTTP), and 443 (HTTPS).

# Initial hardening
ufw default deny incoming
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

# Disable password SSH
sed -i 's/^#*PasswordAuthentication .*/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart ssh

# Install fail2ban for SSH brute-force protection
apt install -y fail2ban

Step 2: Nginx with HTTPS and Auth

Install nginx and certbot. Get a certificate from Let’s Encrypt (free) and set up an auth-gated download path.

# Install
apt install -y nginx certbot python3-certbot-nginx

# Get the cert (replace with your domain)
certbot --nginx -d qa.yourgame.io

# Create a basic auth file
apt install -y apache2-utils
htpasswd -c /etc/nginx/.htpasswd alice
htpasswd /etc/nginx/.htpasswd bob

Then in your nginx server block:

location /builds/ {
    auth_basic "QA Builds";
    auth_basic_user_file /etc/nginx/.htpasswd;
    alias /var/www/qa/builds/;
    autoindex on;
}

location /report/ {
    auth_basic "Bug Reports";
    auth_basic_user_file /etc/nginx/.htpasswd;
    alias /var/www/qa/report/;
    index index.html;
}

Reload nginx. Visiting https://qa.yourgame.io/builds/ now shows a password prompt and, once authenticated, a directory listing of every build artifact.

Step 3: Automated Upload from CI

Add a step to your CI pipeline that uploads the build to the server after a successful build. For GitHub Actions:

- name: Upload to QA server
  uses: appleboy/scp-action@v0.1.4
  with:
    host: qa.yourgame.io
    username: ci
    key: ${{ secrets.QA_SSH_KEY }}
    source: "build/YourGame.exe,build/YourGame_Data.zip"
    target: /var/www/qa/builds/${{ github.run_number }}/

- name: Rotate old builds
  uses: appleboy/ssh-action@v1.0.0
  with:
    host: qa.yourgame.io
    username: ci
    key: ${{ secrets.QA_SSH_KEY }}
    script: |
      cd /var/www/qa/builds
      ls -1dt */ | tail -n +31 | xargs rm -rf

The second step keeps only the last 30 builds so you do not run out of disk.

Create a dedicated ci user on the server with restricted permissions — it should only be able to write to /var/www/qa/builds/.

Step 4: Bug Reports

The simplest option is a static form that emails you:

<form action="https://formspree.io/f/your-id" method="POST">
  <label>Build version: <input type="text" name="version"></label>
  <label>Description: <textarea name="description"></textarea></label>
  <label>Steps: <textarea name="steps"></textarea></label>
  <button type="submit">Submit</button>
</form>

For more advanced setups, wire an in-game reporter to a bug tracker like Bugnet. The reporter sends crash logs, screenshots, and user descriptions directly from the game into a team dashboard.

Step 5: Multiplayer Test Backend (Optional)

If your game has multiplayer, run a dedicated test server on the same VPS (or a separate one for higher specs). Expose it only to the game clients built from trusted commits, and log every connection for later debugging.

Use systemd to manage the process:

# /etc/systemd/system/qa-gameserver.service
[Unit]
Description=QA Game Server
After=network.target

[Service]
Type=simple
User=gameserver
WorkingDirectory=/opt/qa-gameserver
ExecStart=/opt/qa-gameserver/YourGameServer --port 7777 --test-mode
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Enable and start: systemctl enable --now qa-gameserver. Monitor with journalctl -fu qa-gameserver.

Security Notes

A QA server holds pre-release content, so treat it as sensitive:

Total Cost

For a typical indie setup: $10/month VPS, $0 for Let’s Encrypt, $0 for nginx. Optionally $20/month for a second VPS as a game server. $10–30/month total replaces a stack of paid services.

“A QA server is not fancy. It is a Linux box, nginx, and a few lines of CI. The value comes from having your own space where trusted testers can find the latest build and you can control who gets it.”

Related Resources

For build automation, see how to set up automated build testing for games. For broader beta test planning, see how to run a beta test for your indie game. For staging environments, see how to set up a staging environment for game testing.

Watermark every build with the downloader’s username. A leak is much easier to trace when each tester gets a slightly different file.