Docker install
InterDiode provides Docker/OCI images that are available in its private repository. It is possible to always use the latest stable tag or to use another service that handles updating Docker images.
This guide explains the setup based on docker-compose, but the installation of docker-compose itself is out of scope of this documentation. To do this, please follow the official install instructions.
If you want to use the built-in air gap protocol using UDP packets, you are responsible to inject the MAC address in the ARP cache of the host machine, before using the integrated air gap protocol. This must be done on the host machine, not in the Docker container.
Docker-compose file
Here are the Docker-compose files for the black and red instances.
version: '3'
services:
web_interdiodeblack:
image: gitea.interdiode.fr/interdiode/interdiode:latest
volumes:
- ./files:/data/files
- ./transfers/web:/data/transfers
- ./logs/web:/data/logs
- ./tmp/web:/data/tmp
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
command: /bin/sh -c "interdiode-ctl configuration apply --no-input && interdiode-ctl configuration show && interdiode-ctl run http"
depends_on:
- redis_interdiodeblack
- db_interdiodeblack
env_file:
- ./compose-black.env
healthcheck:
test: [CMD, python, -c, "import os; fd = open('/tmp/interdiode-http.pid'); pid=fd.read().strip() ; os.kill(int(pid), 0); fd.close()"]
interval: 60s
timeout: 5s
retries: 10
restart: always
deploy:
resources:
limits:
memory: 2G
background_interdiodeblack:
image: gitea.interdiode.fr/interdiode/interdiode:latest
volumes:
- ./files:/data/files
- ./transfers/shared:/data/transfers
- ./logs/background:/data/logs
- ./tmp/background:/data/tmp
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
command: interdiode-ctl run background
depends_on:
- web_interdiodeblack
- redis_interdiodeblack
- db_interdiodeblack
env_file:
- ./compose-black.env
healthcheck:
test: [CMD, python, -c, "import os; fd = open('/tmp/interdiode-background.pid'); pid=fd.read().strip() ; os.kill(int(pid), 0); fd.close()"]
interval: 60s
timeout: 5s
retries: 10
restart: always
deploy:
resources:
limits:
memory: 10G
beat_interdiodeblack:
image: gitea.interdiode.fr/interdiode/interdiode:latest
volumes:
- ./files:/data/files
- ./transfers/beat:/data/transfers
- ./logs/beat:/data/logs
- ./tmp/beat:/data/tmp
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
command: interdiode-ctl run beat
depends_on:
- web_interdiodeblack
- redis_interdiodeblack
- db_interdiodeblack
env_file:
- ./compose-black.env
healthcheck:
test: [CMD, python, -c, "import os; fd = open('/tmp/interdiode-beat.pid'); pid=fd.read().strip() ; os.kill(int(pid), 0); fd.close()"]
interval: 60s
timeout: 5s
retries: 10
restart: always
deploy:
resources:
limits:
memory: 2G
hairgap_interdiodeblack:
image: gitea.interdiode.fr/interdiode/interdiode:latest
volumes:
- ./files:/data/files
- ./transfers/shared:/data/transfers
- ./logs/hairgap:/data/logs
- ./tmp/hairgap:/data/tmp
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
command: interdiode-ctl hairgap send
depends_on:
- web_interdiodeblack
- redis_interdiodeblack
- db_interdiodeblack
env_file:
- ./compose-black.env
healthcheck:
test: [CMD, python, -c, "import os; fd = open('/tmp/interdiode-hairgap.pid'); pid=fd.read().strip() ; os.kill(int(pid), 0); fd.close()"]
interval: 60s
timeout: 5s
retries: 10
restart: always
deploy:
resources:
limits:
memory: 2G
db_interdiodeblack:
environment:
- POSTGRES_HOST_AUTH_METHOD=trust
- POSTGRES_DB=interdiode_db
- POSTGRES_PASSWORD=my-postgres-password
- POSTGRES_USER=interdiode
- PGDATA=/var/lib/postgresql/data/postgresql
healthcheck:
interval: 60s
retries: 10
test: [CMD, pg_isready, -U, interdiode, -d, interdiode_db]
timeout: 5s
image: postgres:16
restart: always
volumes:
- ./postgres:/var/lib/postgresql/data/postgresql
redis_interdiodeblack:
command: redis-server --requirepass 'my-redis-password' --save 60 1 --loglevel warning
healthcheck:
interval: 60s
retries: 10
test: [CMD, redis-cli, ping]
timeout: 5s
image: redis:alpine
restart: always
volumes:
- ./redis:/data
version: '3'
services:
web_interdiodered:
image: gitea.interdiode.fr/interdiode/interdiode:latest
volumes:
- ./files:/data/files
- ./transfers/web:/data/transfers
- ./logs/web:/data/logs
- ./tmp/web:/data/tmp
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
command: /bin/sh -c "interdiode-ctl configuration apply --no-input && interdiode-ctl configuration show && interdiode-ctl run http"
depends_on:
- redis_interdiodered
- db_interdiodered
env_file:
- ./compose.env
healthcheck:
test: [CMD, python, -c, "import os; fd = open('/tmp/interdiode-http.pid'); pid=fd.read().strip() ; os.kill(int(pid), 0); fd.close()"]
interval: 60s
timeout: 5s
retries: 10
restart: always
deploy:
resources:
limits:
memory: 2G
background_interdiodered:
image: gitea.interdiode.fr/interdiode/interdiode:latest
volumes:
- ./files:/data/files
- ./transfers/shared:/data/transfers
- ./logs/background:/data/logs
- ./tmp/background:/data/tmp
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
command: interdiode-ctl run background
depends_on:
- web_interdiodered
- redis_interdiodered
- db_interdiodered
env_file:
- ./compose.env
healthcheck:
test: [CMD, python, -c, "import os; fd = open('/tmp/interdiode-background.pid'); pid=fd.read().strip() ; os.kill(int(pid), 0); fd.close()"]
interval: 60s
timeout: 5s
retries: 10
restart: always
deploy:
resources:
limits:
memory: 10G
beat_interdiodered:
image: gitea.interdiode.fr/interdiode/interdiode:latest
volumes:
- ./files:/data/files
- ./transfers/beat:/data/transfers
- ./logs/beat:/data/logs
- ./tmp/beat:/data/tmp
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
command: interdiode-ctl run beat
depends_on:
- web_interdiodered
- redis_interdiodered
- db_interdiodered
env_file:
- ./compose.env
healthcheck:
test: [CMD, python, -c, "import os; fd = open('/tmp/interdiode-beat.pid'); pid=fd.read().strip() ; os.kill(int(pid), 0); fd.close()"]
interval: 60s
timeout: 5s
retries: 10
restart: always
deploy:
resources:
limits:
memory: 2G
hairgap_interdiodered:
image: gitea.interdiode.fr/interdiode/interdiode:latest
volumes:
- ./files:/data/files
- ./transfers/shared:/data/transfers
- ./logs/hairgap:/data/logs
- ./tmp/hairgap:/data/tmp
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
command: interdiode-ctl hairgap receive
depends_on:
- web_interdiodered
- redis_interdiodered
- db_interdiodered
env_file:
- ./compose.env
healthcheck:
test: [CMD, python, -c, "import os; fd = open('/tmp/interdiode-hairgap.pid'); pid=fd.read().strip() ; os.kill(int(pid), 0); fd.close()"]
interval: 60s
timeout: 5s
retries: 10
restart: always
deploy:
resources:
limits:
memory: 2G
db_interdiodered:
environment:
- POSTGRES_HOST_AUTH_METHOD=trust
- POSTGRES_DB=interdiode_db
- POSTGRES_PASSWORD=my-postgres-password
- POSTGRES_USER=interdiode
- PGDATA=/var/lib/postgresql/data/postgresql
healthcheck:
interval: 60s
retries: 10
test: [CMD, pg_isready, -U, interdiode, -d, interdiode_db]
timeout: 5s
image: postgres:16
restart: always
volumes:
- ./postgres:/var/lib/postgresql/data/postgresql
redis_interdiodered:
command: redis-server --requirepass 'my-redis-password' --save 60 1 --loglevel warning
healthcheck:
interval: 60s
retries: 10
test: [CMD, redis-cli, ping]
timeout: 5s
image: redis:alpine
restart: always
volumes:
- ./redis:/data
DATABASE_URL=postgres://username:password@localhost:5432/database
# URL of the database: (postgresql|mysql)://user:password@host:port/database
HAIRGAP_DESTINATION_IP=172.20.10.13
# IP address of your red-side InterDiode server
HAIRGAP_DESTINATION_MAC=00:00:00:00:00:00
# MAC address of your red-side InterDiode server
HAIRGAP_DESTINATION_PORT=15124
# Port number of your red-side InterDiode server
LISTEN_ADDRESS=0.0.0.0:8000
# Address listen by your web server (like 127.0.0.1:8000 or :8000).
REDIS_URL=redis://:password@localhost:6379/1
# Redis database URL.
SERVER_BASE_URL=https://interdiode-black.your.domain/
# Public URL of your website.
# Default to "http://{listen_address}/" but should be different if you use a reverse proxy like Apache or Nginx. Example: https://www.example.org/.
SHARED_TRANSFER_KEY=secret_key
# Secret shared between black and red instances for authenticating transfers.
TRANSFER_MODE=udp
# Transfer method: UDP, TCP or manually transfer files. Valid choices: "udp", "tcp", "file"
DATABASE_URL=postgres://username:password@localhost:5432/database
# URL of the database: (postgresql|mysql)://user:password@host:port/database
HAIRGAP_DESTINATION_PORT=15124
# Port number of your red-side InterDiode server
LISTEN_ADDRESS=0.0.0.0:8000
# Address listen by your web server (like 127.0.0.1:8000 or :8000).
REDIS_URL=redis://:password@localhost:6379/1
# Redis database URL.
SERVER_BASE_URL=https://interdiode-red.local/
# Public URL of your website.
# Default to "http://{listen_address}/" but should be different if you use a reverse proxy like Apache or Nginx. Example: https://www.example.org/.
SHARED_TRANSFER_KEY=secret_key
# Secret shared between black and red instances for authenticating transfers.
TRANSFER_MODE=udp
# Transfer method: UDP, TCP or manually transfer files. Valid choices: "udp", "tcp", "file"
Environment
Black side-only parameters:
DATABASE_URL=postgresql://interdiode:interdiode@sql_database_black:5432/interdiode_db
REDIS_URL=redis://:interdiode@redis_database_black/1
INTERDIODE_INTERDIODE_MODE=black
INTERDIODE_SERVER_BASE_URL=http://localhost:8080/
Red side-only parameters:
DATABASE_URL=postgresql://interdiode:interdiode@sql_database_red:5432/interdiode_db
REDIS_URL=redis://:interdiode@redis_database_red/1
INTERDIODE_INTERDIODE_MODE=red
INTERDIODE_SERVER_BASE_URL=http://localhost:8081/
For this demonstration, most settings are common to both instances:
DATABASE_URL=postgresql://interdiode:interdiode@localhost:5432/interdiode_db
EMAIL_HOST_URL=''
INTERDIODE_PLUGINS=''
REDIS_URL=redis://:interdiode@localhost:6379/1
INTERDIODE_USE_HTTP_BASIC_AUTH=true
INTERDIODE_ALLOW_USER_CREATION=true
INTERDIODE_GROUP_DISABLED_ATTRIBUTES=''
INTERDIODE_ALLOW_LOCAL_USERS=true
INTERDIODE_REMOTE_USER_DEFAULT_GROUPS=Users
INTERDIODE_HTTP_REMOTE_USER_HEADER=''
INTERDIODE_USE_AUTHORIZATION_TOKEN=true
INTERDIODE_USER_DISABLED_ATTRIBUTES=''
INTERDIODE_REQUIRE_NEW_USER_VALIDATION=true
INTERDIODE_EMAIL_FROM=admin@localhost
INTERDIODE_ADMIN_EMAIL=admin@localhost
INTERDIODE_DAILY_UPKEEP=true
DATA_ROOT=/data
INTERDIODE_HTML_TITLE=InterDiode
http_proxy=''
INTERDIODE_LANGUAGE_CODE=fr
INTERDIODE_LISTEN_ADDRESS=0.0.0.0:9000
LOG_DIRECTORY=/data/logs/
LOG_LEVEL=warn
INTERDIODE_LOG_REMOTE_ACCESS=true
LOG_REMOTE_URL=''
SENTRY_DSN=''
LOG_SLOW_QUERY_DURATION_IN_S=10.0
MAIN_STORAGE_DIR=/data/files/
INTERDIODE_FILE_UPLOAD_MAX_MEMORY_SIZE=10000000000
INTERDIODE_RUN_DATA_DIR=/tmp/
S3_REGION=''
INTERDIODE_TIME_ZONE=Europe/Paris
INTERDIODE_GNUPG_PATH=gpg
INTERDIODE_SHARED_TRANSFER_KEY=shared_secret_key
INTERDIODE_GIT_ALLOW_LFS=true
INTERDIODE_GIT_PATH=git
INTERDIODE_HIDDEN_CSS_SELECTORS=''
INTERDIODE_KEEP_HAIRGAP_SIZE=10000000000
INTERDIODE_KEEP_SOURCE_ACTION_COUNT=100
INTERDIODE_PURGE_RETENTION_DAYS=30
INTERDIODE_SSH_PATH=ssh
INTERDIODE_HAIRGAP_ERROR_CHUNK_SIZE=''
INTERDIODE_HAIRGAP_DESTINATION_IP=hairgap_red
INTERDIODE_HAIRGAP_DESTINATION_MAC=f0:18:98:a4:38:e2
INTERDIODE_HAIRGAP_DESTINATION_PORT=48102
INTERDIODE_DOWNLOAD_FILE_ANALYZER=''
INTERDIODE_HAIRGAP_END_DELAY_S=5
INTERDIODE_EXPORT_FILE_ANALYZER=''
INTERDIODE_IMPORT_FILE_ANALYZER=''
INTERDIODE_TRANSFER_KEEP_CORRUPTED_IMPORTS=false
INTERDIODE_TRANSFER_KEEP_FAILED_IMPORTS=false
INTERDIODE_TRANSFER_KEEP_IMPORTS=false
INTERDIODE_HAIRGAP_KEEP_TRANSFERS=true
INTERDIODE_KEEP_HAIRGAP_COUNT=100
INTERDIODE_TRANSFER_MODE=udp
INTERDIODE_HAIRGAP_REDUNDANCY=6.0
INTERDIODE_HAIRGAP_TIMEOUT_S=''
INTERDIODE_TRANSFER_DIR=/data/transfers/
INTERDIODE_TRANSFER_EXPORT_CHECKSUMS=true
INTERDIODE_TRANSFER_IMPORT_CHECKSUMS=true
INTERDIODE_DEFAULT_TWITTER_CONSUMER_KEY=''
INTERDIODE_DEFAULT_TWITTER_CONSUMER_SECRET=''
INTERDIODE_DEFAULT_TWITTER_ACCESS_TOKEN_KEY=''
INTERDIODE_DEFAULT_TWITTER_ACCESS_TOKEN_SECRET=''
INTERDIODE_USB_SOURCE_CONFIG_DIR=''
INTERDIODE_WORKER_PROCESSES=2