|
| 1 | +--- |
| 2 | +title: Docker |
| 3 | +description: Run the MSK Discord Ticket Bot in Docker, with compose, volumes and updates |
| 4 | +sidebar_position: 3 |
| 5 | +--- |
| 6 | + |
| 7 | +## 🐳 Running the bot in Docker |
| 8 | + |
| 9 | +Docker is the shortest path to a running bot: no Node installation, no build |
| 10 | +tools for the native SQLite module, and the same image on a VPS, a Raspberry Pi |
| 11 | +or a home server. Images are published for **linux/amd64** and **linux/arm64**. |
| 12 | + |
| 13 | +``` |
| 14 | +ghcr.io/msk-scripts/discord_ticketbot:latest |
| 15 | +``` |
| 16 | + |
| 17 | +Tags follow the releases: `latest` tracks the default branch, `2`, `2.15` and |
| 18 | +`2.15.0` pin as tightly as you want. |
| 19 | + |
| 20 | +--- |
| 21 | + |
| 22 | +### 1. Prepare the directories |
| 23 | + |
| 24 | +The bot keeps two things outside the image: its database and its configuration. |
| 25 | +Both are mounted, so an image update never touches them. |
| 26 | + |
| 27 | +```bash |
| 28 | +mkdir -p ticketbot/config ticketbot/data |
| 29 | +cd ticketbot |
| 30 | +``` |
| 31 | + |
| 32 | +:::info[The container runs as an unprivileged user] |
| 33 | +Inside the image the bot runs as uid 1000, not as root. On Linux the two mounted |
| 34 | +directories have to be writable by that user: |
| 35 | + |
| 36 | +```bash |
| 37 | +sudo chown -R 1000:1000 config data |
| 38 | +``` |
| 39 | + |
| 40 | +Without it the container stops immediately with a message naming the directory |
| 41 | +it cannot write to. That is deliberate: a bot that starts but cannot save |
| 42 | +anything is worse than one that refuses to start. |
| 43 | +::: |
| 44 | + |
| 45 | +--- |
| 46 | + |
| 47 | +### 2. Environment |
| 48 | + |
| 49 | +Create a `.env` next to the compose file: |
| 50 | + |
| 51 | +```bash |
| 52 | +TOKEN=your_discord_bot_token |
| 53 | +CLIENT_ID=your_application_id |
| 54 | +GUILD_ID=your_server_id |
| 55 | + |
| 56 | +# Optional, unlocks the hosted transcript service |
| 57 | +MSK_API_KEY= |
| 58 | +MSK_API_URL=https://www.msk-scripts.de |
| 59 | + |
| 60 | +# Optional. Empty means SQLite in data/tickets.db |
| 61 | +DATABASE_URL= |
| 62 | +``` |
| 63 | + |
| 64 | +--- |
| 65 | + |
| 66 | +### 3. docker-compose.yml |
| 67 | + |
| 68 | +```yaml |
| 69 | +services: |
| 70 | + ticketbot: |
| 71 | + image: ghcr.io/msk-scripts/discord_ticketbot:latest |
| 72 | + container_name: ticketbot |
| 73 | + restart: unless-stopped |
| 74 | + init: true |
| 75 | + env_file: |
| 76 | + - .env |
| 77 | + volumes: |
| 78 | + - ./data:/app/data |
| 79 | + - ./config:/app/config |
| 80 | +``` |
| 81 | +
|
| 82 | +`init: true` matters as soon as you run the dashboard: it forks the bot as a |
| 83 | +child process, and without an init process that child is never reaped. |
| 84 | + |
| 85 | +--- |
| 86 | + |
| 87 | +### 4. First start |
| 88 | + |
| 89 | +```bash |
| 90 | +docker compose up -d |
| 91 | +docker compose logs -f |
| 92 | +``` |
| 93 | + |
| 94 | +On the first start the container copies `config.jsonc` and `snippets.jsonc` into |
| 95 | +your mounted `config/` directory and then stops, because the fresh config still |
| 96 | +contains placeholders. The log names every field it wants: |
| 97 | + |
| 98 | +``` |
| 99 | +[ERROR] Config validation failed: |
| 100 | +[ERROR] - Field "openTicketChannelId" is still the example placeholder ("CHANNEL_ID_HERE"). |
| 101 | +``` |
| 102 | + |
| 103 | +Fill those in (see [Configuration](./configuration.md)), then start again: |
| 104 | + |
| 105 | +```bash |
| 106 | +docker compose up -d |
| 107 | +``` |
| 108 | + |
| 109 | +--- |
| 110 | + |
| 111 | +### 5. The web dashboard |
| 112 | + |
| 113 | +The dashboard is off by default. To use it, add to your `.env`: |
| 114 | + |
| 115 | +```bash |
| 116 | +DASHBOARD_ENABLED=true |
| 117 | +DASHBOARD_HOST=0.0.0.0 |
| 118 | +DASHBOARD_PORT=3010 |
| 119 | +DASHBOARD_PUBLIC_URL=https://tickets.example.com |
| 120 | +CLIENT_SECRET=your_discord_oauth_secret |
| 121 | +``` |
| 122 | + |
| 123 | +and to the compose service: |
| 124 | + |
| 125 | +```yaml |
| 126 | + command: node dashboard.js |
| 127 | + ports: |
| 128 | + - "127.0.0.1:3010:3010" |
| 129 | +``` |
| 130 | + |
| 131 | +:::caution[DASHBOARD_HOST has to be 0.0.0.0 in a container] |
| 132 | +The default `127.0.0.1` is the container's own loopback, which no port mapping |
| 133 | +can reach. Binding to `0.0.0.0` is safe here **because** the published port is |
| 134 | +bound to the host's loopback (`127.0.0.1:3010:3010`); put a reverse proxy with |
| 135 | +TLS in front of it, see [Dashboard](./dashboard.md). |
| 136 | +::: |
| 137 | + |
| 138 | +--- |
| 139 | + |
| 140 | +### 6. Updating |
| 141 | + |
| 142 | +```bash |
| 143 | +docker compose pull |
| 144 | +docker compose up -d |
| 145 | +``` |
| 146 | + |
| 147 | +Your database and config are in the mounts and survive it. |
| 148 | + |
| 149 | +:::note[The update button does not work in Docker] |
| 150 | +The dashboard's update button runs `git pull` and `npm install`. There is no |
| 151 | +checkout inside the container, so in Docker you update by pulling a new image. |
| 152 | +Everything else in the dashboard works normally. |
| 153 | +::: |
| 154 | + |
| 155 | +--- |
| 156 | + |
| 157 | +### 7. Using MariaDB or PostgreSQL instead of SQLite |
| 158 | + |
| 159 | +SQLite is the default and needs nothing. For an external database, add a service |
| 160 | +and point `DATABASE_URL` at it: |
| 161 | + |
| 162 | +```yaml |
| 163 | + mariadb: |
| 164 | + image: mariadb:11 |
| 165 | + restart: unless-stopped |
| 166 | + environment: |
| 167 | + MARIADB_DATABASE: ticketbot |
| 168 | + MARIADB_USER: ticketbot |
| 169 | + MARIADB_PASSWORD: changeme |
| 170 | + MARIADB_RANDOM_ROOT_PASSWORD: "yes" |
| 171 | + volumes: |
| 172 | + - ./data/mariadb:/var/lib/mysql |
| 173 | +``` |
| 174 | + |
| 175 | +```bash |
| 176 | +DATABASE_URL=mysql://ticketbot:changeme@mariadb:3306/ticketbot |
| 177 | +``` |
| 178 | + |
| 179 | +The host name is the service name from the compose file, not `localhost`. See |
| 180 | +[Database](./database.md) for migrating an existing SQLite file. |
| 181 | + |
| 182 | +--- |
| 183 | + |
| 184 | +### Building the image yourself |
| 185 | + |
| 186 | +The repository ships the `Dockerfile`, so a local build works without the |
| 187 | +registry: |
| 188 | + |
| 189 | +```bash |
| 190 | +git clone https://github.com/MSK-Scripts/discord_ticketbot.git |
| 191 | +cd discord_ticketbot |
| 192 | +docker build -t ticketbot . |
| 193 | +``` |
0 commit comments