I had an odd need the other day create a quick temporary web
page to allow someone to upload a file.
After poking around this is what I came up with. (It's not very fancy, and I would not say
it's good for an ongoing production system, but maybe it will help someone out
there)
Install Node/NPM on Ubuntu 14.04
I am going to start this
from the beginning…. All I have is a
freshly installed Ubuntu… no Node Installed no NPM.
Purge (just in case)
> sudo apt-get
--purge remove nodejs
> sudo apt-get
--purge remove npm
|
Update and install node
> sudo apt-get update
> sudo apt-get
install nodejs npm
|
This install nodejs at /usr/bin/nodejs, I would rather have
it at /usr/bin/node so I need to make a link.
> sudo ln -s
/usr/bin/nodejs /usr/bin/node
|
Check the versions
> node -v
> npm -v
|
Make Self Signed SSL certs
I want to run this on
https just to add some security while uploading stuff over the internet.
Here is how you make a
simple self-signed cert on Ubuntu 14.04 see
http://stackoverflow.com/questions/21397809/create-a-self-signed-ssl-cert-for-localhost-for-use-with-express-node [1] for more
information.
> mkdir ssl
> cd ssl
> openssl genrsa
-des3 -out mytest.key 1024
|
When it asks for a passphrase give
it a simple 'password' For example 1234
> openssl req -new
-key mytest.key -out mytest.csr
|
Enter the passphrase
Enter in info when asked
like Country code, state, etc…. you can leave them blank if you wish.
Backup the key and
remove the pass phrase
> cp mytest.key
mytest.key.BACK
> openssl rsa -in
mytest.key.BACK -out mytest.key
|
Enter your passphrase
Sign it, I set it to be
good for 365 days.
> openssl x509 -req
-days 365 -in mytest.csr -signkey mytest.key -out mytest.crt
|
Here are the two you
need the .csr and .key file.
Simple Express page
I like to start
simple… Just get a basic Express page
working.
Create a folder to run
your express app from.
> cd
> mkdir myUploadServer
> cd myUploadServer
|
Initialize the program
> npm init
|
The only important thing
I change is to change index.js to app.js
Install Express
> npm install --save
express
|
Create simple hello
world
> vi app.js
|
And put the following in it.
(tweaked from http://expressjs.com/starter/hello-world.html
[2])
var express = require('express');
var app = express(); //Set Environment app.set('port', 3000); app.get('/', function (req, res) { res.send('Hello World!'); console.log("Responded to request " + req.hostname); }); app.listen(app.get('port'), function () { console.log("Express Server Started Listening on port " + app.get('port')); }); |
Save it and run it
> node app.js
|
Now open up a web page
and point to that server (In my case it's at local IP 192.168.0.195 so I will
open http://192.168.0.195:3000/ )
OK simple web app is
working J
Add in SSL and run on port 443
I found one good site
that gave some insight on how to run express in ssl 'mode'
Install https
> npm install --save
https
> npm install --save
fs
|
Update app.js
> vi app.js
|
var https = require('https');
var fs = require('fs');
var express = require('express');
var app = express();
var options = {
key: fs.readFileSync('ssl/mytest.key'),
cert: fs.readFileSync('ssl/mytest.crt'),
requestCert: false,
rejectUnauthorized: false
};
//Set Environment
app.set('port', 443);
app.get('/', function (req, res) {
res.send('Hello
World!');
console.log("Responded to request " + req.hostname);
});
var server = https.createServer(options, app).listen(app.get('port'),
function(){
console.log("server started at port " + app.get('port'));
});
|
Save it and run it (have to run as sudo since it now is
taking a privileged port < 1024)
> sudo node app.js
|
fs.js:432
return
binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
Oops got an error
v
Oh I forgot to move my ssl certs I made earlier…
Copy the ssl certs
> mkdir ssl
> cp ~/ssl/*.crt ssl/
> cp ~/ssl/*.key ssl/
|
Try it again
> sudo node app.js
|
Now open the https version of
the site.
In my case https://192.168.0.195/
You should get this
warning since it is not signed.
Click on Advanced
And click Proceed
And its working we have
https working in express
Upload a file using multer
Now to create a page that allows us to upload a file to the
server. (This will not be fancy….)
Their github page is at https://github.com/expressjs/multer [4]
I found a few pages going over how to use it.
https://codeforgeek.com/2014/11/file-uploads-using-node-js/ [5] and https://github.com/expressjs/multer/issues/161 [6]
Here is what I came up
with based on these.
First install multer
> npm install --save
multer
|
Create a simple
upload.html file
> vi upload.html
|
<form id = "uploadForm"
enctype =
"multipart/form-data"
action =
"/api/upload"
method =
"post"
>
<input type="file" name="upload-file"
/>
<input type="submit" value="Upload File"
name="submit">
</form>
|
Update app.js
> vi app.js
|
var https = require('https');
var multer = require('multer');
var fs = require('fs');
var express = require('express');
var app = express();
var upload = multer({
dest: 'uploads/'});
var options = {
key:
fs.readFileSync('ssl/mytest.key'),
cert:
fs.readFileSync('ssl/mytest.crt'),
requestCert: false,
rejectUnauthorized:
false
};
var type =
upload.single('upload-file');
app.post('/api/upload',
type, function (req,res) {
console.log("Testing\n " +
req.file.originalname);
console.log(req.file.path);
/** When using the "single"
data come in "req.file"
regardless of the attribute "name". **/
var tmp_path = req.file.path;
/** The original name of the uploaded file
stored in the variable
"originalname". **/
var target_path = 'uploads/' +
req.file.originalname;
/** A better way to copy the uploaded file.
**/
var src = fs.createReadStream(tmp_path);
var dest =
fs.createWriteStream(target_path);
src.pipe(dest);
src.on('end', function() {
res.send('complete'); });
src.on('error', function(err) { res.send('error');
});
});
//Set Environment
app.set('port', 443);
app.get('/upload',function(req,res){
res.sendFile(__dirname +
"/upload.html");
});
var server = https.createServer(options,
app).listen(app.get('port'), function(){
console.log("server
started at port " + app.get('port'));
});
|
OK try and run it
> sudo node app.js
|
Now open
https://192.168.0.195/upload which should
open upload.html
Now choose a file and
click upload.
When it is done it says complete.
Nothing fancy
If I look in the uploads
folder
> ls -alh uploads
|
I see two files
The file with the long
random name is the uploading file… Once the file is uploaded it copies it to a
named file.
That be it.
Although it is using
https for secure transmission it does not block anyone from uploading files via
this node service.
Simple Procedure
Putting this all
together here is a simple procedure to go from nothing on an Ubuntu 14.04
server to a simple node website using a simple self-signed certificate to
upload files. (nothing fancy, no user
accounts not passwords)
Install Node (purge)
> sudo apt-get
update
> sudo apt-get
--purge remove nodejs npm
> sudo apt-get
install nodejs npm
|
This install nodejs at /usr/bin/nodejs, I would rather have
it at /usr/bin/node so I need to make a link.
> sudo ln -s
/usr/bin/nodejs /usr/bin/node
|
Check the versions
> node -v
> npm -v
|
Create node express
projects
> mkdir myUploadServer
> cd myUploadServer
|
Edit package.json
> vi package.json
|
Place the following in
it
{
"name":
"myUploadServer",
"version": "0.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo
\"Error: no test specified\" && exit 1"
},
"author": "",
"license":
"BSD-2-Clause",
"dependencies": {
"express": "~4.13.3",
"https": "~1.0.0",
"fs": "0.0.2",
"multer": "~1.1.0"
}
}
|
Run npm install to grab express/https/fs
> npm Install
|
Create app.js
> vi app.js
|
And place the following
in it.
var https = require('https');
var multer = require('multer');
var fs = require('fs');
var express = require('express');
var app = express();
var upload = multer({ dest: 'uploads/'});
var options = {
key:
fs.readFileSync('ssl/mytest.key'),
cert:
fs.readFileSync('ssl/mytest.crt'),
requestCert: false,
rejectUnauthorized:
false
};
var type = upload.single('upload-file');
app.post('/api/upload',
type, function (req,res) {
console.log("Testing\n " + req.file.originalname);
console.log(req.file.path);
/** When using the
"single"
data come in
"req.file" regardless of the attribute "name". **/
var tmp_path = req.file.path;
/** The original name of
the uploaded file
stored in the
variable "originalname". **/
var target_path =
'uploads/' + req.file.originalname;
/** A better way to copy
the uploaded file. **/
var src =
fs.createReadStream(tmp_path);
var dest =
fs.createWriteStream(target_path);
src.pipe(dest);
src.on('end', function()
{ res.send('complete'); });
src.on('error',
function(err) { res.send('error'); });
});
//Set Environment
app.set('port', 443);
app.get('/upload',function(req,res){
res.sendFile(__dirname + "/upload.html");
});
var server = https.createServer(options,
app).listen(app.get('port'), function(){
console.log("server started at port " + app.get('port'));
});
|
Create a simple
upload.html file
> vi upload.html
|
<form id = "uploadForm"
enctype =
"multipart/form-data"
action =
"/api/upload"
method =
"post"
>
<input type="file" name="upload-file"
/>
<input type="submit" value="Upload File"
name="submit">
</form>
|
Set up ssl (Self signed)
> mkdir ssl
> cd ssl
> openssl genrsa
-des3 -out mytest.key 1024
|
Enter passphrease 1234
> openssl req -new
-key mytest.key -out mytest.csr
|
Enter passphrase and
information you want in SSL key
> cp mytest.key
mytest.key.BACK
> openssl rsa -in
mytest.key.BACK -out mytest.key
|
Enter passphrase
> openssl x509 -req
-days 365 -in mytest.csr -signkey mytest.key -out mytest.crt
> cd ..
|
Run it
> sudo node app.js
|
Now open it in my case
And it works!
Making it prettier with more Feedback?
I used it recently to
upload some very large files. It
worked! I was even able to upload
multiple large files at the same time.
But while they were being uploaded I had no feedback from the web page.
I could go to the server
and see that the files were getting larger but I had no feedback on the web
page itself.
Is there a simple way to
fix this? I would like to have a very
simple node program for uploading large files that I can track…
I poked around and found
a few things. I do not have time at the
moment to fight with it but I thought I would make notes here so I can figure
it out in a month or two… or the next time I have a need for a tool like this.
Looks nice enough…
Here is their github
page
Now how to integrate
it….
Looks like they have a
minimal setup guide
https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin [9]
Oh wait a little more poking led me to npm https://www.npmjs.com/package/blueimp-file-upload [10] The blueimp-file-upload
Oh wait a little more poking led me to npm https://www.npmjs.com/package/blueimp-file-upload [10] The blueimp-file-upload
which then led to
https://www.npmjs.com/package/blueimp-file-upload-expressjs [11]
blueimp-file-upload-expressjs
That looks very
promising!
Oh he made a how to page
http://thejackalofjavascript.com/uploading-files-made-fun [12] That
looks like the place to go figure out how to make it look nicer.
I also found this page
on Express-generator
OK that is it for
research and links… Some day when if I
come back to this I will probably make a nice example in github anyone can grab
and just use.
References
[1] How to create a self-signed certificate
Accessed 12/2015
[2] Hello World Example
Accessed 12/2015
[3] Create a self-signed SSL cert for local
host
Accessed 12/2015
[4] Multer github page
Accessed 12/2015
[5] File Upload
using Nodejs
Accessed 12/2015
[6] Error after 1.0.0
Accessed 12/2015
[7] BlueImp JQuery File Upload page
Accessed 12/2015
[8] BlueImp JQuery File Upload github page
Accessed 12/2015
[9] Minimal setup guide JQuery upload
Accessed 12/2015
[10] blueimp file upload npm page
Accessed 12/2015
[11] blueimp file upload expressjs npm page
Accessed 12/2015
[12] Uploading file made fun with Express js and
Blueimp
Accessed 12/2015
[13] Express Application Generator
No comments:
Post a Comment