Deployment
This guide covers deploying group-ride on a Scaleway instance using Docker Compose, with automatic deployments triggered by a git tag.
Prerequisites
Section titled “Prerequisites”- A Scaleway account
- A GitHub Personal Access Token with
read:packagesscope (to pull the image from GHCR) - Your bot configured — see Installation
Step 1 — Create a Scaleway instance
Section titled “Step 1 — Create a Scaleway instance”A STARDUST1-S (1 vCPU, 1 GB RAM, ~€1.80/month) is sufficient for this bot. A DEV1-S (2 vCPU, 2 GB RAM) gives more headroom if needed.
When creating the instance, select the Docker InstantApp image — Docker and Docker Compose are pre-installed and ready to use.
Once the instance is created, SSH in and verify:
ssh root@<YOUR_INSTANCE_IP>docker --versiondocker compose versionStep 2 — Authenticate to GitHub Container Registry
Section titled “Step 2 — Authenticate to GitHub Container Registry”The Docker image is hosted on GHCR. You need a GitHub Personal Access Token (PAT) to pull it.
- Go to GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
- Generate a token with the
read:packagesscope - On the instance, log in:
echo "<YOUR_PAT>" | docker login ghcr.io -u <YOUR_GITHUB_USERNAME> --password-stdinStep 3 — Set up the deployment directory
Section titled “Step 3 — Set up the deployment directory”mkdir -p /opt/group-ride && cd /opt/group-rideCreate the .env file:
cat > .env <<EOFDISCORD_TOKEN=your_bot_tokenDISCORD_CLIENT_ID=your_client_idDISCORD_GUILD_ID=your_server_idDISCORD_ANNOUNCEMENT_CHANNEL_ID=your_announcement_channel_idDISCORD_FORUM_CHANNEL_ID=your_forum_channel_idDATABASE_PATH=/app/data/group-ride.db# DATABASE_URL=postgres://user:password@your-db-host:5432/group_rideTZ=Europe/ParisEOFKeep this file private — it contains your bot token.
Download the Compose file:
curl -fsSL https://raw.githubusercontent.com/Slashgear/group-ride/main/docker-compose.yml -o docker-compose.ymlStep 4 — Start the bot
Section titled “Step 4 — Start the bot”docker compose pulldocker compose up -dCheck that it is running:
docker compose psdocker compose logs -fYou should see:
Group Ride bot is runningStep 5 — Enable automatic deployments (CI/CD)
Section titled “Step 5 — Enable automatic deployments (CI/CD)”The release workflow (tag → test → GitHub release → Docker image → deploy) is already set up. The deploy job SSHes into your instance and runs docker compose pull && docker compose up -d. You just need to give it the credentials.
5a — Generate a dedicated SSH key pair
Section titled “5a — Generate a dedicated SSH key pair”On your local machine (not the instance):
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/group-ride-deploy -N ""This creates two files:
~/.ssh/group-ride-deploy— private key (goes to GitHub)~/.ssh/group-ride-deploy.pub— public key (goes to the instance)
5b — Authorise the key on the instance
Section titled “5b — Authorise the key on the instance”ssh root@<YOUR_INSTANCE_IP> "echo '$(cat ~/.ssh/group-ride-deploy.pub)' >> ~/.ssh/authorized_keys"5c — Add secrets to GitHub
Section titled “5c — Add secrets to GitHub”Go to GitHub → your repo → Settings → Secrets and variables → Actions and add:
| Secret name | Value |
|---|---|
DEPLOY_HOST |
Your instance IP address |
DEPLOY_SSH_KEY |
Contents of ~/.ssh/group-ride-deploy (the private key) |
5d — Configure the GitHub environment
Section titled “5d — Configure the GitHub environment”The deploy job uses the production environment, which lets you add protection rules (e.g. manual approval before each deploy).
Go to GitHub → Settings → Environments → production and configure as needed. If you skip this, the job still runs — the environment is optional.
Releasing a new version
Section titled “Releasing a new version”Once everything is set up, releasing is a single command from your local machine:
# 1. Bump the version in package.json# e.g. change "version": "0.2.0" to "0.3.0"
# 2. Commit, then tag and pushbun run releaseThis triggers the full pipeline: tests → GitHub release → Docker image → SSH deploy.
Useful commands
Section titled “Useful commands”# View live logsdocker compose logs -f
# Stop the botdocker compose down
# Restartdocker compose restart
# Open a shell in the running containerdocker compose exec bot shSQLite data
Section titled “SQLite data”The database is stored in a named Docker volume (group-ride_data) and persists across container restarts and image updates. To back it up:
docker run --rm \ -v group-ride_data:/data \ -v $(pwd):/backup \ busybox tar czf /backup/group-ride-backup-$(date +%Y%m%d).tar.gz /dataPostgreSQL data
Section titled “PostgreSQL data”If you set DATABASE_URL, the bot connects to your PostgreSQL instance instead of SQLite — no volume needed. Run the migrations once before starting the bot:
for f in src/adapters/database/postgres/migrations/*.sql; do psql "$DATABASE_URL" -f "$f"doneFor backup, use your provider’s snapshot feature or pg_dump:
pg_dump "$DATABASE_URL" > group-ride-backup-$(date +%Y%m%d).sql