Android HTTP File Server using NanoHTTPD + Jetpack Compose
Build an HTTP server on Android to upload large files using NanoHTTPD and Jetpack Compose UI, Kotlin SDL

Android HTTP & File Server using NanoHTTPD + Jetpack Compose
In this post, weโll walk through how to build an HTTP server inside an Android app using NanoHTTPD and a modern Jetpack Compose UI, Kotlin DSL, capable of uploading large files over 10GB directly to the device's internal storage.
๐งฉ Tech Stack
- ๐ง NanoHTTPD: Lightweight Java HTTP server
- ๐ผ Jetpack Compose: Declarative Kotlin UI framework
- ๐ ViewModel & Kotlin DSL: For clean state and UI control
- ๐ Custom File Upload Logic: Efficient streaming to disk
๐ Source Code on GitHub https://github.com/WPSeven/Android-Http-File-Server
๐ Why This?
Mobile apps typically don't expose HTTP endpoints, but with custom tooling, you can:
- Turn your phone into a local file server
- Receive large files over Wi-Fi
- Avoid needing ADB or USB transfers for big files (like 10GB+ videos)
๐ฆ Core Server Logic (NanoHTTPD)
We extend NanoHTTPD and override serve()
to handle multipart/form-data
uploads.
HttpServer.java
public class HttpServer extends NanoHTTPD {
public HttpServer(int port, Context context, UploadCallback callback) {
super(port);
// Store context, callback
}
@Override
public Response serve(IHTTPSession session) {
// Handle file uploads using NanoFileUpload
}
}
This is backed by a NanoFileUpload helper that uses streaming APIs to save files directly to disk without memory overflows.
๐พ Streaming File Uploads
To handle large files, we stream the file upload chunk by chunk.
NanoFileUpload.java
public void handleUpload(IHTTPSession session) {
// Parse multipart content using NanoHTTPD's TempFileManager
// Write input stream directly to a FileOutputStream
}
๐ง Jetpack Compose UI
Your app includes a clean Kotlin DSL-based UI using Jetpack Compose to control the server.
MainScreen.kt
@Composable
fun MainScreen(viewModel: MainViewModel) {
Column {
Text("Android File Server")
Button(onClick = { viewModel.toggleServer() }) {
Text(if (viewModel.isRunning) "Stop Server" else "Start Server")
}
Text("Status: ${viewModel.statusText}")
}
}
๐ง ViewModel Orchestration
MainViewModel.kt
class MainViewModel : ViewModel() {
private var server: HttpServer? = null
fun toggleServer() {
if (server == null) {
startServer()
} else {
stopServer()
}
}
private fun startServer() {
server = HttpServer(8080, context, uploadCallback)
server?.start()
}
}
The server is toggled via ViewModel, ensuring lifecycle-aware control.
โ๏ธ Handling Large File Uploads (Up to 10GB+)
The core feature is robust large file upload support. Here's what powers it under the hood:
โ Multipart Upload Handling
We configure DiskFileItemFactory
and NanoFileUpload
to support very large uploads (10GB):
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024 * 1024); // 1MB memory buffer
factory.setRepository(mContext.getCacheDir()); // Temp storage
mFileUpload = new NanoFileUpload(factory);
mFileUpload.setFileSizeMax(10L * 1024 * 1024 * 1024); // 10GB
We also attach a ProgressListener to emit real-time upload progress back to the UI:
mFileUpload.setProgressListener((bytesRead, contentLength, items) -> {
int progress = (int) (bytesRead * 100 / contentLength);
mStatusUpdateListener.onUploadingProgressUpdate(progress);
});
๐ง HTML + JS File Upload UI (Web Browser)
When you visit / in a browser, the server responds with an HTML page that includes an upload form and a progress bar, using pure JS:
<form onsubmit='return uploadFile();'>
<input type='file' id='fileInput' name='file'><br>
<input type='submit' value='Upload File'>
</form>
<div class='progress'>
<div id='progressBar' class='progress-bar'></div>
</div>
JavaScript handles the progress updates:
xhr.upload.onprogress = function(e) {
var percentComplete = (e.loaded / e.total) * 100;
document.getElementById('progressBar').style.width = percentComplete + '%';
};
๐ Upload Streaming & Disk Write
To save the uploaded file in chunks:
private static final int BUFFER_SIZE = 1024 * 1024;
private static final int CHUNK_SIZE = 10 * 1024 * 1024;
private void copyInputStreamToFile(InputStream input, File file, long contentLength) throws IOException {
try (FileOutputStream output = new FileOutputStream(file)) {
byte[] buffer = new byte[BUFFER_SIZE];
long count = 0;
long lastProgressUpdate = 0;
int n;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
// Update progress less frequently to reduce UI updates
long currentTime = System.currentTimeMillis();
if (currentTime - lastProgressUpdate > 500) { // Update every 500ms
int progress = (int)((count * 100) / contentLength);
if (mStatusUpdateListener != null) {
mStatusUpdateListener.onUploadingProgressUpdate(progress);
}
lastProgressUpdate = currentTime;
}
// Add small delay between large chunks to prevent buffer overflow
if (count % CHUNK_SIZE == 0) {
Thread.sleep(50);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
๐ก Uploading Files to Android from PC using browser or command-line Once running:
- Find your Android deviceโs IP on Wi-Fi.
- Use browser or curl:
Browser 'http://192.168.1.175:8080/'
๐ธ Screenshot:


Command-line
curl -F "file=@bigfile.iso" http://192.168.1.x:8080
This is critical for handling large files without crashing.
With just a few files, you can turn your Android device into a full-fledged local http file server.
๐งฑ Source Code on GitHub https://github.com/WPSeven/Android-Http-File-Server
๐ก #Kotlin #Compose #Android #HttpServer #FileServer #DevTips