Hey there,
I’d like to use Nix to build a Flutter application in a reproducible manner. For this I am using Nix flakes inside of Docker.
The setup:
Flutter pubspec.yaml
name: some_flutter_app
dependencies:
flutter:
sdk: flutter
some_private_package:
git:
url: git@bitbucket.org:some_org/some_private_package.git
A Nix flake (excuse the mess, I’ve been tinkering with this)
{
description = "Flutter development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
config = {
allowUnfree = true;
};
};
in
{
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
# Flutter SDK and dependencies
flutter
dart
# Additional tools
jq
just
cocoapods
# Ensure SSH is available
openssh
git
];
# Environment variables
shellHook = ''
echo "Flutter development environment loaded"
export PUB_CACHE=$HOME/.pub-cache
export PATH=$PATH:$PUB_CACHE/bin
'';
};
packages = {
default = self.packages.${system}.some-app;
# Include the SSH test in the all-packages build
all-packages = pkgs.symlinkJoin {
name = "all-packages";
paths = [
self.packages.${system}.some-app
];
};
some-app = pkgs.stdenv.mkDerivation {
name = "some-app";
src = ./.; # Source is the current directory
nativeBuildInputs = with pkgs; [
flutter
dart
cacert
makeWrapper
# Add SSH and Git support
openssh
git
];
# For Docker build, allow SSH agent passthrough
__noChroot = true;
buildPhase = ''
# Create a temporary home directory for Flutter
export HOME=$(mktemp -d)
export PUB_CACHE=$HOME/.pub-cache
# Enable SSH agent forwarding for private git dependencies
export SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock
mkdir -p $PUB_CACHE
# Setup certificates for Dart/Flutter according to nixpkgs recommendation
# Create a wrapper for dart with certificate path
mkdir -p $HOME/bin
cat > $HOME/bin/dart-with-certs <<EOF
#!${pkgs.bash}/bin/bash
exec ${pkgs.dart}/bin/dart --root-certs-file=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt "\$@"
EOF
chmod +x $HOME/bin/dart-with-certs
# Tell Flutter to use our wrapped Dart for pub commands
export NIX_FLUTTER_PUB_DART="$HOME/bin/dart-with-certs"
export PATH=$HOME/bin:$PATH
# Setup SSH for Git dependencies
# This assumes SSH agent is forwarded or keys are available
mkdir -p $HOME/.ssh
chmod 700 $HOME/.ssh
# Create SSH config to disable host key checking for Bitbucket
cat > $HOME/.ssh/config <<EOF
Host bitbucket.org
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
EOF
chmod 600 $HOME/.ssh/config
# Add BitBucket to known hosts explicitly (can help in some environments)
${pkgs.openssh}/bin/ssh-keyscan bitbucket.org >> $HOME/.ssh/known_hosts
# Configure Git to use our SSH setup and specify the path to SSH
export GIT_SSH_COMMAND="${pkgs.openssh}/bin/ssh -F $HOME/.ssh/config"
# Disable analytics and configure Flutter
flutter config --no-analytics >/dev/null
flutter pub get
# Build the app (using linux for compatibility)
flutter build linux --release
'';
meta = {
description = "";
platforms = pkgs.flutter.meta.platforms;
};
};
};
}
);
}
and a Docker file:
FROM nixos/nix
# Enable Nix flakes
RUN echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf
RUN nix-env -iA nixpkgs.cacert nixpkgs.openssh
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
ENV PATH=$PATH:/root/.nix-profile/bin
COPY . /app/
WORKDIR /app
# Add bitbucket.org's host key to known_hosts before cloning
RUN --mount=type=ssh \
sh -c "mkdir -p -m 0700 ~/.ssh && ssh-keyscan bitbucket.org >> ~/.ssh/known_hosts"
# Check if has correct git ssh rights
RUN --mount=type=ssh \
sh -c "ssh -vT git@bitbucket.org && git ls-remote git+ssh://git@bitbucket.org/some_org/some_private_package.git"
RUN --mount=type=ssh nix build --extra-experimental-features 'nix-command flakes' .#ssh-test
# Default command to start a shell
CMD ["bash"]
SSH works correctly inside Docker, and I do have access to the private repository from within the container. However, as I understand it, Nix handles SSH and the SSH agent in a specific way. This prevents the git tool used by Flutter to pull dependencies from receiving the necessary SSH keys.
My questions are:
- Is this an ‘intended’ setup? Or am I missing something fundamental?
- How do I get the SSH keys loaded so Flutter can use them to pull private dependencies?
Thanks,
Norbert